@open-wa/wa-automate 4.30.12 → 4.31.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.
@@ -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
- let browser, wapiInjected = false, wapiAttempts = 1;
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.addScriptTag({
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 check = `window.WAPI && window.Store ? true : false`;
288
- const wapi = yield (0, tools_1.timePromise)(() => (0, exports.addScript)(page, 'wapi.js'));
289
- spinner === null || spinner === void 0 ? void 0 : spinner.info(`WAPI inject: ${wapi}ms`);
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: 200 }).catch(e => false));
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;
@@ -301,10 +362,11 @@ function injectWapi(page, spinner, force = false) {
301
362
  exports.injectWapi = injectWapi;
302
363
  function injectApi(page, spinner, force = false) {
303
364
  return __awaiter(this, void 0, void 0, function* () {
365
+ spinner === null || spinner === void 0 ? void 0 : spinner.info("Injecting scripts");
304
366
  yield injectPreApiScripts(page, spinner);
305
367
  yield injectWapi(page, spinner, force);
306
368
  const launch = yield (0, tools_1.timePromise)(() => (0, exports.addScript)(page, 'launch.js'));
307
- spinner === null || spinner === void 0 ? void 0 : spinner.info(`Launch inject: ${launch}ms`);
369
+ spinner === null || spinner === void 0 ? void 0 : spinner.succeed(`Launch inject: ${launch}ms`);
308
370
  return page;
309
371
  });
310
372
  }
@@ -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* () {
@@ -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 };
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
+ return new (P || (P = Promise))(function (resolve, reject) {
24
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
28
+ });
29
+ };
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.scriptLoader = exports.ScriptLoader = void 0;
32
+ const path = __importStar(require("path"));
33
+ const fs = __importStar(require("fs"));
34
+ const logging_1 = require("../logging/logging");
35
+ const read = (_path) => new Promise((resolve, reject) => {
36
+ fs.readFile(require.resolve(path.join(__dirname, '../lib', _path)), 'utf8', (err, file) => {
37
+ if (err)
38
+ reject(err);
39
+ resolve(file);
40
+ });
41
+ });
42
+ class ScriptLoader {
43
+ constructor() {
44
+ this.scripts = [
45
+ // stage 1
46
+ 'axios.min.js',
47
+ 'jsSha.min.js',
48
+ 'qr.min.js',
49
+ 'base64.js',
50
+ 'hash.js',
51
+ //stage 2
52
+ 'wapi.js',
53
+ //stage 3,
54
+ 'launch.js'
55
+ ];
56
+ this.contentRegistry = {};
57
+ this.contentRegistry = {};
58
+ }
59
+ loadScripts() {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ yield Promise.all(this.scripts.map(this.getScript.bind(this)));
62
+ return this.contentRegistry;
63
+ });
64
+ }
65
+ getScript(scriptName) {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ if (!this.contentRegistry[scriptName]) {
68
+ this.contentRegistry[scriptName] = yield read(scriptName);
69
+ logging_1.log.info("SCRIPT READY: " + scriptName);
70
+ }
71
+ return this.contentRegistry[scriptName];
72
+ });
73
+ }
74
+ flush() {
75
+ this.contentRegistry = {};
76
+ }
77
+ getScripts() {
78
+ return this.contentRegistry;
79
+ }
80
+ }
81
+ exports.ScriptLoader = ScriptLoader;
82
+ const scriptLoader = new ScriptLoader();
83
+ exports.scriptLoader = scriptLoader;