@open-wa/wa-automate 4.30.13 → 4.31.3

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,34 @@ 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
+ try {
136
+ if (response.request().url() == "https://web.whatsapp.com/") {
137
+ const t = yield response.text();
138
+ if (t.includes(`class="no-js"`) && t.includes(`self.`) && !dumbCache) {
139
+ //this is a valid response, save it for later
140
+ dumbCache = t;
141
+ logging_1.log.info("saving valid page to dumb cache");
142
+ }
143
+ }
144
+ }
145
+ catch (error) {
146
+ logging_1.log.error("dumb cache error", error);
147
+ }
148
+ }));
110
149
  const authCompleteEv = new events_1.EvEmitter(sessionId, 'AUTH');
111
150
  waPage.on('request', (request) => __awaiter(this, void 0, void 0, function* () {
151
+ //local refresh cache:
152
+ if (request.url() === "https://web.whatsapp.com/" && dumbCache) {
153
+ //if the dumbCache isn't set and this response includes
154
+ logging_1.log.info("reviving page from dumb cache");
155
+ return yield request.respond({
156
+ status: 200,
157
+ body: dumbCache
158
+ });
159
+ }
112
160
  if (interceptAuthentication &&
113
161
  request.url().includes('_priority_components') &&
114
162
  !quickAuthed) {
@@ -184,7 +232,6 @@ function initPage(sessionId, config, customUserAgent, spinner, _page, skipAuth)
184
232
  //try twice
185
233
  const WEB_START_TS = new Date().getTime();
186
234
  const webRes = yield waPage.goto(puppeteer_config_1.puppeteerConfig.WAUrl);
187
- Promise.all([injectApi(waPage, spinner), auth_1.qrManager.waitFirstQr(waPage, config, spinner)]);
188
235
  const WEB_END_TS = new Date().getTime();
189
236
  if (webRes == null) {
190
237
  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 +309,15 @@ const getSessionDataFilePath = (sessionId, config) => {
262
309
  return false;
263
310
  };
264
311
  exports.getSessionDataFilePath = getSessionDataFilePath;
265
- const addScript = (page, js) => page.addScriptTag({
266
- path: require.resolve(path.join(__dirname, '../lib', js))
267
- });
312
+ const addScript = (page, js) => __awaiter(void 0, void 0, void 0, function* () { return page.evaluate(yield script_preloader_1.scriptLoader.getScript(js)); });
268
313
  exports.addScript = addScript;
314
+ // (page: Page, js : string) : Promise<unknown> => page.addScriptTag({
315
+ // path: require.resolve(path.join(__dirname, '../lib', js))
316
+ // })
269
317
  function injectPreApiScripts(page, spinner) {
270
318
  return __awaiter(this, void 0, void 0, function* () {
319
+ if (yield page.evaluate("!['jsSHA','axios', 'QRCode', 'Base64', 'objectHash'].find(x=>!window[x])"))
320
+ return;
271
321
  const t1 = yield (0, tools_1.timePromise)(() => Promise.all([
272
322
  'axios.min.js',
273
323
  'jsSha.min.js',
@@ -282,17 +332,33 @@ function injectPreApiScripts(page, spinner) {
282
332
  exports.injectPreApiScripts = injectPreApiScripts;
283
333
  function injectWapi(page, spinner, force = false) {
284
334
  return __awaiter(this, void 0, void 0, function* () {
335
+ const bruteInjectionAttempts = 1;
336
+ yield (0, patch_manager_1.earlyInjectionCheck)(page);
337
+ const check = `window.WAPI && window.Store ? true : false`;
338
+ const initCheck = yield page.evaluate(check);
339
+ if (initCheck)
340
+ return;
341
+ logging_1.log.info(`WAPI CHECK: ${initCheck}`);
342
+ if (!check)
343
+ force = true;
285
344
  if (wapiInjected && !force)
286
345
  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`);
346
+ const multiScriptInjectPromiseArr = Array(bruteInjectionAttempts).fill("wapi.js").map((_s) => (0, exports.addScript)(page, _s));
347
+ try {
348
+ const wapi = yield (0, tools_1.timePromise)(() => Promise.all(multiScriptInjectPromiseArr));
349
+ spinner === null || spinner === void 0 ? void 0 : spinner.info(`WAPI inject: ${wapi}ms`);
350
+ }
351
+ catch (error) {
352
+ logging_1.log.error("injectWapi ~ error", error.message);
353
+ //one of the injection attempts failed.
354
+ return yield injectWapi(page, spinner, force);
355
+ }
290
356
  spinner === null || spinner === void 0 ? void 0 : spinner.info("Checking session integrity");
291
357
  wapiAttempts++;
292
- wapiInjected = !!(yield page.waitForFunction(check, { timeout: 3000, polling: 200 }).catch(e => false));
358
+ wapiInjected = !!(yield page.waitForFunction(check, { timeout: 3000, polling: 50 }).catch(e => false));
293
359
  if (!wapiInjected) {
294
360
  spinner === null || spinner === void 0 ? void 0 : spinner.info(`Session integrity check failed, trying again... ${wapiAttempts}`);
295
- return yield injectWapi(page, spinner);
361
+ return yield injectWapi(page, spinner, true);
296
362
  }
297
363
  spinner === null || spinner === void 0 ? void 0 : spinner.info("Session integrity check passed");
298
364
  return page;
@@ -301,10 +367,11 @@ function injectWapi(page, spinner, force = false) {
301
367
  exports.injectWapi = injectWapi;
302
368
  function injectApi(page, spinner, force = false) {
303
369
  return __awaiter(this, void 0, void 0, function* () {
370
+ spinner === null || spinner === void 0 ? void 0 : spinner.info("Injecting scripts");
304
371
  yield injectPreApiScripts(page, spinner);
305
372
  yield injectWapi(page, spinner, force);
306
373
  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`);
374
+ spinner === null || spinner === void 0 ? void 0 : spinner.succeed(`Launch inject: ${launch}ms`);
308
375
  return page;
309
376
  });
310
377
  }
@@ -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;