@open-wa/wa-automate 4.30.10 → 4.31.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/README.md +3 -3
- package/bin/config-schema.json +1 -1
- package/dist/api/Client.d.ts +28 -40
- package/dist/api/Client.js +30 -43
- package/dist/api/model/aliases.d.ts +10 -6
- package/dist/api/model/aliases.js +1 -0
- package/dist/api/model/config.d.ts +4 -1
- package/dist/api/model/index.d.ts +1 -0
- package/dist/api/model/index.js +1 -0
- package/dist/api/model/product.d.ts +1 -1
- package/dist/cli/cli-options.d.ts +9 -0
- package/dist/cli/cli-options.js +229 -0
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +7 -232
- package/dist/controllers/auth.d.ts +5 -1
- package/dist/controllers/auth.js +26 -9
- package/dist/controllers/browser.js +72 -11
- package/dist/controllers/initializer.js +3 -1
- package/dist/controllers/patch_manager.js +3 -1
- package/dist/controllers/script_preloader.d.ts +17 -0
- package/dist/controllers/script_preloader.js +83 -0
- package/dist/lib/wapi.js +3 -3
- package/package.json +13 -13
package/dist/cli/setup.js
CHANGED
@@ -44,242 +44,17 @@ const events_1 = require("../controllers/events");
|
|
44
44
|
const is_url_superb_1 = __importDefault(require("is-url-superb"));
|
45
45
|
const path = __importStar(require("path"));
|
46
46
|
const logging_1 = require("../logging/logging");
|
47
|
+
const cli_options_1 = require("./cli-options");
|
47
48
|
let checkUrl = url => typeof url === 'string' ? (0, is_url_superb_1.default)(url) : false;
|
48
49
|
const configWithCases = (0, fs_extra_1.readJsonSync)(path.join(__dirname, '../../bin/config-schema.json'));
|
49
|
-
|
50
|
-
|
51
|
-
default: false,
|
52
|
-
alias: 'n',
|
53
|
-
type: Boolean,
|
54
|
-
description: "Don't expose the api. This may be useful if you just want to set the webhooks."
|
55
|
-
}, {
|
56
|
-
name: 'bot-press-url',
|
57
|
-
alias: 'b',
|
58
|
-
type: String,
|
59
|
-
typeLabel: '{blue {underline http://localhost:3000/api/v1/bots/cool-bot}}',
|
60
|
-
description: "The Botpress URL that ends with your bot id."
|
61
|
-
}, {
|
62
|
-
name: 'twilio-webhook',
|
63
|
-
alias: 't',
|
64
|
-
type: String,
|
65
|
-
typeLabel: '{blue {underline http://localhost:5555/incoming}}',
|
66
|
-
description: "Send twillio payloads to this URL. EASY API will also parse and processes twillio response message payloads."
|
67
|
-
}, {
|
68
|
-
name: 'chatwoot-url',
|
69
|
-
type: String,
|
70
|
-
typeLabel: '{blue {underline http://localhost:3000/api/v1/accounts/3/inboxes/1}}',
|
71
|
-
description: "The URL of the specific Chatwoot inbox you set up for this session"
|
72
|
-
}, {
|
73
|
-
name: 'chatwoot-api-access-token',
|
74
|
-
type: String,
|
75
|
-
typeLabel: '{blue {underline mEEwUGEEML2ZThMm252rLg1M}}',
|
76
|
-
description: "The access token of the specific Chatwoot inbox you set up for this session"
|
77
|
-
},
|
78
|
-
{
|
79
|
-
name: 'port',
|
80
|
-
alias: 'p',
|
81
|
-
default: 8002,
|
82
|
-
type: Number,
|
83
|
-
typeLabel: '{blue {underline 8080}}',
|
84
|
-
description: "Set the port for the api. Default to 8002."
|
85
|
-
},
|
86
|
-
{
|
87
|
-
name: 'api-host',
|
88
|
-
type: String,
|
89
|
-
typeLabel: '{yellow {underline localhost}}',
|
90
|
-
description: "The easy API may be sitting behind a reverse proxy. In this case set --api-host in order to make sure the api docs and api explorer are working properly. You will need to include the protocol as well."
|
91
|
-
},
|
92
|
-
{
|
93
|
-
name: 'host',
|
94
|
-
alias: 'h',
|
95
|
-
default: 'localhost',
|
96
|
-
type: String,
|
97
|
-
typeLabel: '{red {underline localhost}}',
|
98
|
-
description: "Set the hostname for the api documantation and statistics. Overrides --api-host. Default: localhost."
|
99
|
-
},
|
100
|
-
{
|
101
|
-
name: 'webhook',
|
102
|
-
alias: 'w',
|
103
|
-
type: String,
|
104
|
-
typeLabel: '{yellow {underline https://webhook.site/....}}',
|
105
|
-
description: "Webhook to use for the listeners."
|
106
|
-
},
|
107
|
-
{
|
108
|
-
name: 'ev',
|
109
|
-
alias: 'e',
|
110
|
-
type: String,
|
111
|
-
typeLabel: '{green {underline https://webhook.site/....}}',
|
112
|
-
description: "Send launch events to this URL."
|
113
|
-
},
|
114
|
-
{
|
115
|
-
name: 'ef',
|
116
|
-
type: String,
|
117
|
-
//@ts-ignore
|
118
|
-
default: ["qr", "STARTUP"],
|
119
|
-
isMultiple: true,
|
120
|
-
typeLabel: '{blueBright {underline qr,STARTUP}}',
|
121
|
-
description: "Filters which namespaces trigger the webhook set in -e/--ev."
|
122
|
-
},
|
123
|
-
{
|
124
|
-
name: 'allow-session-data-wh',
|
125
|
-
alias: 'x',
|
126
|
-
default: false,
|
127
|
-
type: Boolean,
|
128
|
-
description: "By default, if you set -e flag, the session data is not transferred to the webhook as it is extremely sensitive data. In order to bypass this security measure, use this flag."
|
129
|
-
},
|
130
|
-
{
|
131
|
-
name: 'key',
|
132
|
-
alias: 'k',
|
133
|
-
type: String,
|
134
|
-
typeLabel: '{redBright {underline apikey}}',
|
135
|
-
description: "Specify an api key to use as a check for all requests. If you add -k by itself, a key will be autogenerated for you."
|
136
|
-
},
|
137
|
-
{
|
138
|
-
name: 'config',
|
139
|
-
alias: 'c',
|
140
|
-
type: String,
|
141
|
-
typeLabel: '{yellowBright {underline ./config.json}}',
|
142
|
-
description: "The relative json file that contains the config. By default the system will look for config.json which will override any config variables set. Default: './config.json'."
|
143
|
-
},
|
144
|
-
{
|
145
|
-
name: 'session',
|
146
|
-
alias: 's',
|
147
|
-
type: String,
|
148
|
-
typeLabel: '{magentaBright {underline BASE64}}',
|
149
|
-
description: "A base64 string representing the session data."
|
150
|
-
},
|
151
|
-
{
|
152
|
-
name: 'keep-alive',
|
153
|
-
alias: 'a',
|
154
|
-
type: Boolean,
|
155
|
-
description: "If true, the system will force the session to refocus in this process. This will prevent you from opening a session elsewhere."
|
156
|
-
},
|
157
|
-
{
|
158
|
-
name: 'use-session-id-in-path',
|
159
|
-
alias: 'i',
|
160
|
-
type: Boolean,
|
161
|
-
description: "If true, all API paths will include the session id. default to false and the default session Id is 'session'."
|
162
|
-
},
|
163
|
-
{
|
164
|
-
name: 'generate-api-docs',
|
165
|
-
alias: 'd',
|
166
|
-
type: Boolean,
|
167
|
-
default: true,
|
168
|
-
description: "Generate postman collection and expose api docs to open in browser."
|
169
|
-
},
|
170
|
-
{
|
171
|
-
name: 'session-data-only',
|
172
|
-
alias: 'o',
|
173
|
-
type: Boolean,
|
174
|
-
description: "Kill the process when the session data is saved.",
|
175
|
-
default: false
|
176
|
-
},
|
177
|
-
{
|
178
|
-
name: 'skip-save-postman-collection',
|
179
|
-
type: Boolean,
|
180
|
-
description: "Don't save the postman collection.",
|
181
|
-
default: false
|
182
|
-
},
|
183
|
-
{
|
184
|
-
name: 'headful',
|
185
|
-
type: Boolean,
|
186
|
-
description: "Show the browser window on your machine.",
|
187
|
-
default: false
|
188
|
-
},
|
189
|
-
{
|
190
|
-
name: 'headful',
|
191
|
-
type: Boolean,
|
192
|
-
description: "Pre authenticate documentation site [High security risk]."
|
193
|
-
},
|
194
|
-
{
|
195
|
-
name: 'stats',
|
196
|
-
type: Boolean,
|
197
|
-
description: "Exposes API swagger-statistics.",
|
198
|
-
default: false
|
199
|
-
},
|
200
|
-
{
|
201
|
-
name: 'pre-auth-docs',
|
202
|
-
type: Boolean,
|
203
|
-
description: "Grab config options from the environment variables.",
|
204
|
-
default: false
|
205
|
-
},
|
206
|
-
{
|
207
|
-
name: 'no-kill-on-logout',
|
208
|
-
type: Boolean,
|
209
|
-
description: "Keeps the process alive when host account logs out of session. default is false",
|
210
|
-
default: false
|
211
|
-
},
|
212
|
-
{
|
213
|
-
name: 'debug',
|
214
|
-
type: Boolean,
|
215
|
-
description: "Print out the CLI flag values and the WA_* env vars. default is false",
|
216
|
-
default: false
|
217
|
-
},
|
218
|
-
{
|
219
|
-
name: 'cors',
|
220
|
-
type: Boolean,
|
221
|
-
description: "Enable all cors requests",
|
222
|
-
default: false
|
223
|
-
},
|
224
|
-
{
|
225
|
-
name: 'socket',
|
226
|
-
type: Boolean,
|
227
|
-
description: "Expose a socket.io middleware on the server.",
|
228
|
-
default: false
|
229
|
-
},
|
230
|
-
{
|
231
|
-
name: 'license-key',
|
232
|
-
alias: 'l',
|
233
|
-
type: String,
|
234
|
-
typeLabel: '{yellowBright {underline B2BJ4JFB-2UN2J3ND-2J5I.....}}',
|
235
|
-
description: "The license key you want to use for this server. License keys are used to unlock features. Learn more here https://github.com/open-wa/wa-automate-nodejs#license-key"
|
236
|
-
},
|
237
|
-
{
|
238
|
-
name: 'ready-webhook',
|
239
|
-
type: String,
|
240
|
-
typeLabel: '{yellow {underline https://webhook.site/....}}',
|
241
|
-
description: "Webhook that fires when the EASY API is completely ready"
|
242
|
-
},
|
243
|
-
{
|
244
|
-
name: 'on-call',
|
245
|
-
type: String,
|
246
|
-
typeLabel: '{yellow {underline "Please do not call this number"}}',
|
247
|
-
description: "A default message to send to any number that is trying to call the host account"
|
248
|
-
},
|
249
|
-
{
|
250
|
-
name: 'auto-reject',
|
251
|
-
type: Boolean,
|
252
|
-
description: "Automatically reject incoming phone and video calls to the host account."
|
253
|
-
},
|
254
|
-
{
|
255
|
-
name: 'emit-unread',
|
256
|
-
type: Boolean,
|
257
|
-
description: "Emit all unread messages via onMessage webhooks on launch.",
|
258
|
-
default: false
|
259
|
-
},
|
260
|
-
{
|
261
|
-
name: 'skip-url-check',
|
262
|
-
type: Boolean,
|
263
|
-
description: "Don't validate webhook URLs. Enables use of non-FQDNs."
|
264
|
-
},
|
265
|
-
{
|
266
|
-
name: 'tunnel',
|
267
|
-
type: Boolean,
|
268
|
-
description: "Expose a tunnel to your EASY API session - this is for testing and it is unsecured."
|
269
|
-
},
|
270
|
-
{
|
271
|
-
name: 'help',
|
272
|
-
description: 'Print this usage guide.'
|
273
|
-
}
|
274
|
-
];
|
275
|
-
exports.optionKeys = optionList.map(({ name }) => (0, tools_1.camelize)(name));
|
276
|
-
exports.optionKeysWithDefalts = [...optionList.filter(o => o.hasOwnProperty('default')).map(({ name }) => (0, tools_1.camelize)(name)), 'popup'];
|
50
|
+
exports.optionKeys = cli_options_1.optionList.map(({ name }) => (0, tools_1.camelize)(name));
|
51
|
+
exports.optionKeysWithDefalts = [...cli_options_1.optionList.filter(o => o.hasOwnProperty('default')).map(({ name }) => (0, tools_1.camelize)(name)), 'popup'];
|
277
52
|
exports.PrimitiveConverter = {
|
278
53
|
Number: 1,
|
279
54
|
Boolean: true,
|
280
55
|
String: "hello"
|
281
56
|
};
|
282
|
-
exports.cliOptionNames = optionList.reduce((acc, c) => {
|
57
|
+
exports.cliOptionNames = cli_options_1.optionList.reduce((acc, c) => {
|
283
58
|
if (!c.type)
|
284
59
|
return acc;
|
285
60
|
acc[(0, tools_1.camelize)(c.name)] = typeof exports.PrimitiveConverter[c.type.name];
|
@@ -299,7 +74,7 @@ const meowFlags = () => {
|
|
299
74
|
};
|
300
75
|
});
|
301
76
|
const res = {};
|
302
|
-
optionList.map(option => {
|
77
|
+
cli_options_1.optionList.map(option => {
|
303
78
|
var _a, _b;
|
304
79
|
res[(0, tools_1.camelize)(option.name)] = Object.assign(Object.assign({}, option), {
|
305
80
|
//@ts-ignore
|
@@ -314,7 +89,7 @@ exports.helptext = (0, command_line_usage_1.default)([{
|
|
314
89
|
},
|
315
90
|
{
|
316
91
|
header: '',
|
317
|
-
optionList
|
92
|
+
optionList: cli_options_1.optionList
|
318
93
|
},
|
319
94
|
{
|
320
95
|
header: "Session config flags",
|
@@ -383,7 +158,7 @@ const cli = () => {
|
|
383
158
|
* 3. CLI flags
|
384
159
|
*/
|
385
160
|
const nonCliConfigs = Object.assign(Object.assign({}, (0, exports.envArgs)()), ((0, exports.configFile)(_cli.flags.config) || {}));
|
386
|
-
optionList.filter(option => option.default);
|
161
|
+
cli_options_1.optionList.filter(option => option.default);
|
387
162
|
const cliConfig = Object.assign(Object.assign(Object.assign({ sessionId: "session" }, nonCliConfigs), _cli.flags), exports.optionKeysWithDefalts.reduce((p, c) => nonCliConfigs.hasOwnProperty(c) ? Object.assign(Object.assign({}, p), { [c]: nonCliConfigs[c] }) : p, {}));
|
388
163
|
//firstly set up logger
|
389
164
|
if (cliConfig === null || cliConfig === void 0 ? void 0 : cliConfig.logging) {
|
@@ -3,13 +3,13 @@ import { Spin } from './events';
|
|
3
3
|
import { ConfigObject } from '../api/model';
|
4
4
|
import { Page } from 'puppeteer';
|
5
5
|
/**
|
6
|
+
* isAuthenticated
|
6
7
|
* Validates if client is authenticated
|
7
8
|
* @returns true if is authenticated, false otherwise
|
8
9
|
* @param waPage
|
9
10
|
*/
|
10
11
|
export declare const isAuthenticated: (waPage: Page) => Promise<unknown>;
|
11
12
|
export declare const needsToScan: (waPage: Page) => Observable<unknown>;
|
12
|
-
export declare const isInsideChat: (waPage: Page) => Observable<boolean>;
|
13
13
|
export declare const waitForRipeSession: (waPage: Page) => Promise<boolean>;
|
14
14
|
export declare const sessionDataInvalid: (waPage: Page) => Promise<string>;
|
15
15
|
export declare const phoneIsOutOfReach: (waPage: Page) => Promise<boolean>;
|
@@ -27,6 +27,10 @@ export declare class QRManager {
|
|
27
27
|
grabAndEmit(qrData: any, waPage: Page, config: ConfigObject, spinner: Spin): Promise<void>;
|
28
28
|
smartQr(waPage: Page, config?: ConfigObject, spinner?: Spin): Promise<boolean | void | string>;
|
29
29
|
emitFirst(waPage: Page, config?: ConfigObject, spinner?: Spin): Promise<void>;
|
30
|
+
/**
|
31
|
+
* Wait 10 seconds for the qr element to show.
|
32
|
+
* If it doesn't show up within 10 seconds then assume the session is authed already or blocked therefore ignore and return promise
|
33
|
+
*/
|
30
34
|
waitFirstQr(waPage: Page, config?: ConfigObject, spinner?: Spin): Promise<void>;
|
31
35
|
}
|
32
36
|
export declare const qrManager: QRManager;
|
package/dist/controllers/auth.js
CHANGED
@@ -31,7 +31,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
31
31
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
32
32
|
};
|
33
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
34
|
-
exports.qrManager = exports.QRManager = exports.phoneIsOutOfReach = exports.sessionDataInvalid = exports.waitForRipeSession = exports.
|
34
|
+
exports.qrManager = exports.QRManager = exports.phoneIsOutOfReach = exports.sessionDataInvalid = exports.waitForRipeSession = exports.needsToScan = exports.isAuthenticated = void 0;
|
35
35
|
const qrcode = __importStar(require("qrcode-terminal"));
|
36
36
|
const rxjs_1 = require("rxjs");
|
37
37
|
const events_1 = require("./events");
|
@@ -41,11 +41,12 @@ const browser_1 = require("./browser");
|
|
41
41
|
const axios_1 = __importDefault(require("axios"));
|
42
42
|
const logging_1 = require("../logging/logging");
|
43
43
|
/**
|
44
|
+
* isAuthenticated
|
44
45
|
* Validates if client is authenticated
|
45
46
|
* @returns true if is authenticated, false otherwise
|
46
47
|
* @param waPage
|
47
48
|
*/
|
48
|
-
const isAuthenticated = (waPage) => (0, rxjs_1.race)((0, exports.needsToScan)(waPage),
|
49
|
+
const isAuthenticated = (waPage) => (0, rxjs_1.race)((0, exports.needsToScan)(waPage), isInsideChat(waPage), (0, exports.sessionDataInvalid)(waPage)).toPromise();
|
49
50
|
exports.isAuthenticated = isAuthenticated;
|
50
51
|
const needsToScan = (waPage) => {
|
51
52
|
return (0, rxjs_1.from)(new Promise((resolve) => __awaiter(void 0, void 0, void 0, function* () {
|
@@ -72,7 +73,11 @@ const isInsideChat = (waPage) => {
|
|
72
73
|
.waitForFunction("!!window.WA_AUTHENTICATED || (document.getElementsByClassName('app')[0] && document.getElementsByClassName('app')[0].attributes && !!document.getElementsByClassName('app')[0].attributes.tabindex) || (document.getElementsByClassName('two')[0] && document.getElementsByClassName('two')[0].attributes && !!document.getElementsByClassName('two')[0].attributes.tabindex)", { timeout: 0 })
|
73
74
|
.then(() => true));
|
74
75
|
};
|
75
|
-
|
76
|
+
const isTosBlocked = (waPage) => {
|
77
|
+
return (0, rxjs_1.from)(waPage
|
78
|
+
.waitForFunction(`document.getElementsByTagName("html")[0].classList[0] === 'no-js'`, { timeout: 0 })
|
79
|
+
.then(() => false));
|
80
|
+
};
|
76
81
|
const waitForRipeSession = (waPage) => __awaiter(void 0, void 0, void 0, function* () {
|
77
82
|
try {
|
78
83
|
yield waPage.waitForFunction(`window.isRipeSession()`, { timeout: 0, polling: 'mutation' });
|
@@ -84,11 +89,17 @@ const waitForRipeSession = (waPage) => __awaiter(void 0, void 0, void 0, functio
|
|
84
89
|
});
|
85
90
|
exports.waitForRipeSession = waitForRipeSession;
|
86
91
|
const sessionDataInvalid = (waPage) => __awaiter(void 0, void 0, void 0, function* () {
|
92
|
+
const check = `Object.keys(localStorage).includes("old-logout-cred")`;
|
87
93
|
yield waPage
|
88
|
-
.waitForFunction(
|
89
|
-
|
90
|
-
|
91
|
-
|
94
|
+
.waitForFunction(check, { timeout: 0, polling: 'mutation' });
|
95
|
+
// await injectApi(waPage, null, true);
|
96
|
+
// await waPage
|
97
|
+
// .waitForFunction(
|
98
|
+
// '!window.getQrPng',
|
99
|
+
// { timeout: 0, polling: 'mutation' }
|
100
|
+
// )
|
101
|
+
// await timeout(1000000)
|
102
|
+
//NEED A DIFFERENT WAY TO DETERMINE IF THE SESSION WAS LOGGED OUT!!!!
|
92
103
|
//if the code reaches here it means the browser was refreshed. Nuke the session data and restart `create`
|
93
104
|
return 'NUKE';
|
94
105
|
});
|
@@ -116,6 +127,7 @@ class QRManager {
|
|
116
127
|
this.qrEvF(this.config);
|
117
128
|
}
|
118
129
|
qrEvF(config = this.config) {
|
130
|
+
return new events_1.EvEmitter(config.sessionId || 'session', 'qr');
|
119
131
|
if (!this.qrEv)
|
120
132
|
this.qrEv = new events_1.EvEmitter(config.sessionId || 'session', 'qr');
|
121
133
|
return this.qrEv;
|
@@ -205,12 +217,13 @@ class QRManager {
|
|
205
217
|
const fn = (qrData) => __awaiter(this, void 0, void 0, function* () {
|
206
218
|
if (qrData.length > 200 && !(config === null || config === void 0 ? void 0 : config.multiDevice)) {
|
207
219
|
spinner.fail(`Multi-Device detected, please set multiDevice to true in your config or add the --multi-device flag`);
|
220
|
+
spinner.emit(true, "MD_DETECT");
|
208
221
|
return resolve(md);
|
209
222
|
}
|
210
223
|
if (!gotResult && (qrData === 'QR_CODE_SUCCESS' || qrData === md)) {
|
211
224
|
gotResult = true;
|
212
225
|
spinner === null || spinner === void 0 ? void 0 : spinner.succeed(qrData === md ? "Multi device support for this project is EXPERIMENTAL. Some things may not work...." : "QR code scanned. Loading session...");
|
213
|
-
return resolve(yield
|
226
|
+
return resolve(yield isInsideChat(waPage).toPromise());
|
214
227
|
}
|
215
228
|
if (!gotResult)
|
216
229
|
this.grabAndEmit(qrData, waPage, config, spinner);
|
@@ -238,13 +251,17 @@ class QRManager {
|
|
238
251
|
yield this.grabAndEmit(firstQr, waPage, config, spinner);
|
239
252
|
});
|
240
253
|
}
|
254
|
+
/**
|
255
|
+
* Wait 10 seconds for the qr element to show.
|
256
|
+
* If it doesn't show up within 10 seconds then assume the session is authed already or blocked therefore ignore and return promise
|
257
|
+
*/
|
241
258
|
waitFirstQr(waPage, config, spinner) {
|
242
259
|
return __awaiter(this, void 0, void 0, function* () {
|
243
260
|
const fqr = yield waPage.waitForFunction(`!!(${this.qrCheck})`, {
|
244
261
|
polling: 500,
|
245
262
|
timeout: 10000
|
246
263
|
})
|
247
|
-
.catch(
|
264
|
+
.catch(() => false);
|
248
265
|
if (fqr)
|
249
266
|
yield this.emitFirst(waPage, config, spinner);
|
250
267
|
return;
|
@@ -45,12 +45,15 @@ const promise_1 = __importDefault(require("terminate/promise"));
|
|
45
45
|
const logging_1 = require("../logging/logging");
|
46
46
|
const tools_1 = require("../utils/tools");
|
47
47
|
const auth_1 = require("./auth");
|
48
|
-
|
48
|
+
const script_preloader_1 = require("./script_preloader");
|
49
|
+
const patch_manager_1 = require("./patch_manager");
|
50
|
+
let browser, wapiInjected = false, dumbCache = undefined, wapiAttempts = 1;
|
49
51
|
exports.BROWSER_START_TS = 0;
|
50
52
|
function initPage(sessionId, config, customUserAgent, spinner, _page, skipAuth) {
|
51
53
|
var _a, _b, _c, _d, _e;
|
52
54
|
return __awaiter(this, void 0, void 0, function* () {
|
53
55
|
const setupPromises = [];
|
56
|
+
script_preloader_1.scriptLoader.loadScripts();
|
54
57
|
if ((config === null || config === void 0 ? void 0 : config.resizable) === undefined || !(config === null || config === void 0 ? void 0 : config.resizable) == false)
|
55
58
|
config.defaultViewport = null;
|
56
59
|
if (config === null || config === void 0 ? void 0 : config.useStealth) {
|
@@ -65,7 +68,28 @@ function initPage(sessionId, config, customUserAgent, spinner, _page, skipAuth)
|
|
65
68
|
spinner === null || spinner === void 0 ? void 0 : spinner.info(`Browser launched: ${((0, tools_1.now)() - startBrowser).toFixed(0)}ms`);
|
66
69
|
waPage = yield getWAPage(browser);
|
67
70
|
}
|
71
|
+
//@ts-ignore
|
72
|
+
waPage._client.send('Network.setBypassServiceWorker', { bypass: true });
|
68
73
|
const postBrowserLaunchTs = (0, tools_1.now)();
|
74
|
+
waPage.on("framenavigated", (frame) => __awaiter(this, void 0, void 0, function* () {
|
75
|
+
try {
|
76
|
+
const frameNavPromises = [];
|
77
|
+
const content = yield frame.content();
|
78
|
+
const webpPackKey = (((content.match(/self.(?:.*)=self.*\|\|\[\]/g) || [])[0] || "").match(/self.*\w?=/g) || [""])[0].replace("=", "").replace("self.", "") || false;
|
79
|
+
logging_1.log.info(`FRAME NAV, ${frame.url()}, ${webpPackKey}`);
|
80
|
+
if (webpPackKey) {
|
81
|
+
frameNavPromises.push(injectApi(waPage, spinner, true));
|
82
|
+
frameNavPromises.push(auth_1.qrManager.waitFirstQr(waPage, config, spinner));
|
83
|
+
}
|
84
|
+
if (frame.url().includes('post_logout=1')) {
|
85
|
+
console.log("Session most likely logged out");
|
86
|
+
}
|
87
|
+
yield Promise.all(frameNavPromises);
|
88
|
+
}
|
89
|
+
catch (error) {
|
90
|
+
logging_1.log.error('framenaverr', error);
|
91
|
+
}
|
92
|
+
}));
|
69
93
|
spinner === null || spinner === void 0 ? void 0 : spinner.info('Setting Up Page');
|
70
94
|
if (config === null || config === void 0 ? void 0 : config.proxyServerCredentials) {
|
71
95
|
yield waPage.authenticate(config.proxyServerCredentials);
|
@@ -105,10 +129,29 @@ function initPage(sessionId, config, customUserAgent, spinner, _page, skipAuth)
|
|
105
129
|
if (proxyAddr) {
|
106
130
|
proxy = (yield Promise.resolve().then(() => __importStar(require('puppeteer-page-proxy')))).default;
|
107
131
|
}
|
108
|
-
if (interceptAuthentication || proxyAddr || blockCrashLogs) {
|
132
|
+
if (interceptAuthentication || proxyAddr || blockCrashLogs || true) {
|
109
133
|
yield waPage.setRequestInterception(true);
|
134
|
+
waPage.on('response', (response) => __awaiter(this, void 0, void 0, function* () {
|
135
|
+
if (response.request().url() == "https://web.whatsapp.com/") {
|
136
|
+
const t = yield response.text();
|
137
|
+
if (t.includes(`class="no-js"`) && t.includes(`self.`) && !dumbCache) {
|
138
|
+
//this is a valid response, save it for later
|
139
|
+
dumbCache = t;
|
140
|
+
logging_1.log.info("saving valid page to dumb cache");
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}));
|
110
144
|
const authCompleteEv = new events_1.EvEmitter(sessionId, 'AUTH');
|
111
145
|
waPage.on('request', (request) => __awaiter(this, void 0, void 0, function* () {
|
146
|
+
//local refresh cache:
|
147
|
+
if (request.url() === "https://web.whatsapp.com/" && dumbCache) {
|
148
|
+
//if the dumbCache isn't set and this response includes
|
149
|
+
logging_1.log.info("reviving page from dumb cache");
|
150
|
+
return yield request.respond({
|
151
|
+
status: 200,
|
152
|
+
body: dumbCache
|
153
|
+
});
|
154
|
+
}
|
112
155
|
if (interceptAuthentication &&
|
113
156
|
request.url().includes('_priority_components') &&
|
114
157
|
!quickAuthed) {
|
@@ -184,7 +227,6 @@ function initPage(sessionId, config, customUserAgent, spinner, _page, skipAuth)
|
|
184
227
|
//try twice
|
185
228
|
const WEB_START_TS = new Date().getTime();
|
186
229
|
const webRes = yield waPage.goto(puppeteer_config_1.puppeteerConfig.WAUrl);
|
187
|
-
Promise.all([injectApi(waPage, spinner), auth_1.qrManager.waitFirstQr(waPage, config, spinner)]);
|
188
230
|
const WEB_END_TS = new Date().getTime();
|
189
231
|
if (webRes == null) {
|
190
232
|
spinner === null || spinner === void 0 ? void 0 : spinner.info(`Page loaded but something may have gone wrong: ${WEB_END_TS - WEB_START_TS}ms`);
|
@@ -262,12 +304,15 @@ const getSessionDataFilePath = (sessionId, config) => {
|
|
262
304
|
return false;
|
263
305
|
};
|
264
306
|
exports.getSessionDataFilePath = getSessionDataFilePath;
|
265
|
-
const addScript = (page, js) => page.
|
266
|
-
path: require.resolve(path.join(__dirname, '../lib', js))
|
267
|
-
});
|
307
|
+
const addScript = (page, js) => __awaiter(void 0, void 0, void 0, function* () { return page.evaluate(yield script_preloader_1.scriptLoader.getScript(js)); });
|
268
308
|
exports.addScript = addScript;
|
309
|
+
// (page: Page, js : string) : Promise<unknown> => page.addScriptTag({
|
310
|
+
// path: require.resolve(path.join(__dirname, '../lib', js))
|
311
|
+
// })
|
269
312
|
function injectPreApiScripts(page, spinner) {
|
270
313
|
return __awaiter(this, void 0, void 0, function* () {
|
314
|
+
if (yield page.evaluate("!['jsSHA','axios', 'QRCode', 'Base64', 'objectHash'].find(x=>!window[x])"))
|
315
|
+
return;
|
271
316
|
const t1 = yield (0, tools_1.timePromise)(() => Promise.all([
|
272
317
|
'axios.min.js',
|
273
318
|
'jsSha.min.js',
|
@@ -282,17 +327,33 @@ function injectPreApiScripts(page, spinner) {
|
|
282
327
|
exports.injectPreApiScripts = injectPreApiScripts;
|
283
328
|
function injectWapi(page, spinner, force = false) {
|
284
329
|
return __awaiter(this, void 0, void 0, function* () {
|
330
|
+
const bruteInjectionAttempts = 1;
|
331
|
+
yield (0, patch_manager_1.earlyInjectionCheck)(page);
|
332
|
+
const check = `window.WAPI && window.Store ? true : false`;
|
333
|
+
const initCheck = yield page.evaluate(check);
|
334
|
+
if (initCheck)
|
335
|
+
return;
|
336
|
+
logging_1.log.info(`WAPI CHECK: ${initCheck}`);
|
337
|
+
if (!check)
|
338
|
+
force = true;
|
285
339
|
if (wapiInjected && !force)
|
286
340
|
return page;
|
287
|
-
const
|
288
|
-
|
289
|
-
|
341
|
+
const multiScriptInjectPromiseArr = Array(bruteInjectionAttempts).fill("wapi.js").map((_s) => (0, exports.addScript)(page, _s));
|
342
|
+
try {
|
343
|
+
const wapi = yield (0, tools_1.timePromise)(() => Promise.all(multiScriptInjectPromiseArr));
|
344
|
+
spinner === null || spinner === void 0 ? void 0 : spinner.info(`WAPI inject: ${wapi}ms`);
|
345
|
+
}
|
346
|
+
catch (error) {
|
347
|
+
logging_1.log.error("injectWapi ~ error", error.message);
|
348
|
+
//one of the injection attempts failed.
|
349
|
+
return yield injectWapi(page, spinner, force);
|
350
|
+
}
|
290
351
|
spinner === null || spinner === void 0 ? void 0 : spinner.info("Checking session integrity");
|
291
352
|
wapiAttempts++;
|
292
|
-
wapiInjected = !!(yield page.waitForFunction(check, { timeout: 3000, polling:
|
353
|
+
wapiInjected = !!(yield page.waitForFunction(check, { timeout: 3000, polling: 50 }).catch(e => false));
|
293
354
|
if (!wapiInjected) {
|
294
355
|
spinner === null || spinner === void 0 ? void 0 : spinner.info(`Session integrity check failed, trying again... ${wapiAttempts}`);
|
295
|
-
return yield injectWapi(page, spinner);
|
356
|
+
return yield injectWapi(page, spinner, true);
|
296
357
|
}
|
297
358
|
spinner === null || spinner === void 0 ? void 0 : spinner.info("Session integrity check passed");
|
298
359
|
return page;
|
@@ -363,7 +363,7 @@ function create(config = {}) {
|
|
363
363
|
waPage.on('error', error => {
|
364
364
|
if (config === null || config === void 0 ? void 0 : config.logConsoleErrors)
|
365
365
|
console.error(error);
|
366
|
-
logging_1.log.error('Page Console Error:', error.text());
|
366
|
+
logging_1.log.error('Page Console Error:', error.message || (error === null || error === void 0 ? void 0 : error.text()));
|
367
367
|
});
|
368
368
|
if (config === null || config === void 0 ? void 0 : config.restartOnCrash)
|
369
369
|
waPage.on('error', (error) => __awaiter(this, void 0, void 0, function* () {
|
@@ -401,6 +401,8 @@ function create(config = {}) {
|
|
401
401
|
config.eventMode = true;
|
402
402
|
const client = new Client_1.Client(waPage, config, debugInfo);
|
403
403
|
const { me } = yield client.getMe();
|
404
|
+
const licIndex = process.argv.findIndex(arg => arg === "--license-key" || arg === "-l");
|
405
|
+
config.licenseKey = config.licenseKey || licIndex !== -1 && process.argv[licIndex + 1];
|
404
406
|
if ((config === null || config === void 0 ? void 0 : config.licenseKey) || me._serialized !== earlyWid) {
|
405
407
|
yield (0, patch_manager_1.getAndInjectLicense)(waPage, config, me, debugInfo, spinner, me._serialized !== earlyWid ? false : yield licensePromise);
|
406
408
|
}
|
@@ -164,6 +164,8 @@ function getLicense(config, me, debugInfo, spinner) {
|
|
164
164
|
exports.getLicense = getLicense;
|
165
165
|
function earlyInjectionCheck(page) {
|
166
166
|
return __awaiter(this, void 0, void 0, function* () {
|
167
|
+
//@ts-ignore
|
168
|
+
yield page.waitForFunction(() => Object.entries(window).filter(([, o]) => o && o.push && (o.push != [].push))[0] ? true : false, { timeout: 10, polling: 500 }).catch(() => { });
|
167
169
|
//@ts-ignore
|
168
170
|
return yield page.evaluate(() => { if (window.webpackChunkwhatsapp_web_client) {
|
169
171
|
window.webpackChunkbuild = window.webpackChunkwhatsapp_web_client;
|
@@ -172,7 +174,7 @@ function earlyInjectionCheck(page) {
|
|
172
174
|
(function () { const f = Object.entries(window).filter(([, o]) => o && o.push && (o.push != [].push)); if (f[0]) {
|
173
175
|
window.webpackChunkbuild = window[f[0][0]];
|
174
176
|
} })();
|
175
|
-
} return (typeof webpackChunkbuild !== "undefined"); });
|
177
|
+
} return (typeof window.webpackChunkbuild !== "undefined"); });
|
176
178
|
});
|
177
179
|
}
|
178
180
|
exports.earlyInjectionCheck = earlyInjectionCheck;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
export declare class ScriptLoader {
|
2
|
+
scripts: string[];
|
3
|
+
contentRegistry: {
|
4
|
+
[key: string]: string;
|
5
|
+
};
|
6
|
+
constructor();
|
7
|
+
loadScripts(): Promise<{
|
8
|
+
[key: string]: string;
|
9
|
+
}>;
|
10
|
+
getScript(scriptName: string): Promise<string>;
|
11
|
+
flush(): void;
|
12
|
+
getScripts(): {
|
13
|
+
[key: string]: string;
|
14
|
+
};
|
15
|
+
}
|
16
|
+
declare const scriptLoader: ScriptLoader;
|
17
|
+
export { scriptLoader };
|