@open-wa/wa-automate 4.67.0 → 4.68.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -10,6 +10,8 @@
10
10
  >
11
11
  >
12
12
 
13
+ [![Ceasefire Now](https://badge.techforpalestine.org/ceasefire-now)](https://techforpalestine.org/learn-more)
14
+
13
15
  [![npm version](https://img.shields.io/npm/v/@open-wa/wa-automate.svg?color=green)](https://www.npmjs.com/package/@open-wa/wa-automate)
14
16
  ![node](https://img.shields.io/node/v/@open-wa/wa-automate)
15
17
  [![Downloads](https://img.shields.io/npm/dm/@open-wa/wa-automate.svg)](https://www.npmjs.com/package/@open-wa/wa-automate)
@@ -1883,15 +1883,7 @@ export declare class Client {
1883
1883
  */
1884
1884
  sendGiphyAsSticker(to: ChatId, giphyMediaUrl: URL | string): Promise<MessageId | string | boolean>;
1885
1885
  /**
1886
- * @deprecated
1887
- *
1888
- * :::danger
1889
- *
1890
- * Status features are broken for now. Please join our discord community for updates.
1891
- *
1892
- * :::
1893
- *
1894
- * [REQUIRES A TEXT STORY LICENSE-KEY](https://gum.co/open-wa)
1886
+ * {@license:restricted@}
1895
1887
  *
1896
1888
  * Sends a formatted text story.
1897
1889
  * @param text The text to be displayed in the story
@@ -1908,15 +1900,7 @@ export declare class Client {
1908
1900
  */
1909
1901
  postTextStatus(text: Content, textRgba: string, backgroundRgba: string, font: number): Promise<MessageId | string | boolean>;
1910
1902
  /**
1911
- * @deprecated
1912
- *
1913
- * :::danger
1914
- *
1915
- * Status features are broken for now. Please join our discord community for updates.
1916
- *
1917
- * :::
1918
- *
1919
- * [REQUIRES AN IMAGE STORY LICENSE-KEY](https://gum.co/open-wa)
1903
+ * {@license:restricted@}
1920
1904
  *
1921
1905
  * Posts an image story.
1922
1906
  * @param data data url string `data:[<MIME-type>][;charset=<encoding>][;base64],<data>`
@@ -1925,15 +1909,7 @@ export declare class Client {
1925
1909
  */
1926
1910
  postImageStatus(data: DataURL, caption: Content): Promise<MessageId | string | boolean>;
1927
1911
  /**
1928
- * @deprecated
1929
- *
1930
- * :::danger
1931
- *
1932
- * Status features are broken for now. Please join our discord community for updates.
1933
- *
1934
- * :::
1935
- *
1936
- * [REQUIRES A VIDEO STORY LICENSE-KEY](https://gum.co/open-wa)
1912
+ * {@license:restricted@}
1937
1913
  *
1938
1914
  * Posts a video story.
1939
1915
  * @param data data url string `data:[<MIME-type>][;charset=<encoding>][;base64],<data>`
@@ -1951,7 +1927,6 @@ export declare class Client {
1951
1927
  */
1952
1928
  deleteStory(statusesToDelete: string | string[]): Promise<boolean>;
1953
1929
  /**
1954
- * @deprecated
1955
1930
  * Alias for deleteStory
1956
1931
  */
1957
1932
  deleteStatus(statusesToDelete: string | string[]): Promise<boolean>;
@@ -1963,7 +1938,6 @@ export declare class Client {
1963
1938
  */
1964
1939
  deleteAllStories(): Promise<boolean>;
1965
1940
  /**
1966
- * @deprecated
1967
1941
  * Alias for deleteStory
1968
1942
  */
1969
1943
  deleteAllStatus(): Promise<boolean>;
@@ -1976,7 +1950,6 @@ export declare class Client {
1976
1950
  */
1977
1951
  getMyStoryArray(): Promise<Message[]>;
1978
1952
  /**
1979
- * @deprecated
1980
1953
  * Alias for deleteStory
1981
1954
  */
1982
1955
  getMyStatusArray(): Promise<Message[]>;
@@ -1859,12 +1859,12 @@ class Client {
1859
1859
  let thumb;
1860
1860
  try {
1861
1861
  linkData = (yield axios_1.default.get(`${((_a = this._createConfig) === null || _a === void 0 ? void 0 : _a.linkParser) || "https://link.openwa.cloud/api"}?url=${url}`)).data;
1862
- logging_1.log.info("Got link data", linkData);
1862
+ logging_1.log.info("Got link data");
1863
1863
  if (!thumbnail)
1864
1864
  thumb = yield (0, tools_1.getDUrl)(linkData.image);
1865
1865
  }
1866
1866
  catch (error) {
1867
- logging_1.log.error(error);
1867
+ console.error(error);
1868
1868
  }
1869
1869
  if (linkData && (thumbnail || thumb))
1870
1870
  return yield this.sendMessageWithThumb(thumbnail || thumb, url, linkData.title, linkData.description, text, to);
@@ -3823,15 +3823,7 @@ class Client {
3823
3823
  });
3824
3824
  }
3825
3825
  /**
3826
- * @deprecated
3827
- *
3828
- * :::danger
3829
- *
3830
- * Status features are broken for now. Please join our discord community for updates.
3831
- *
3832
- * :::
3833
- *
3834
- * [REQUIRES A TEXT STORY LICENSE-KEY](https://gum.co/open-wa)
3826
+ * {@license:restricted@}
3835
3827
  *
3836
3828
  * Sends a formatted text story.
3837
3829
  * @param text The text to be displayed in the story
@@ -3852,15 +3844,7 @@ class Client {
3852
3844
  });
3853
3845
  }
3854
3846
  /**
3855
- * @deprecated
3856
- *
3857
- * :::danger
3858
- *
3859
- * Status features are broken for now. Please join our discord community for updates.
3860
- *
3861
- * :::
3862
- *
3863
- * [REQUIRES AN IMAGE STORY LICENSE-KEY](https://gum.co/open-wa)
3847
+ * {@license:restricted@}
3864
3848
  *
3865
3849
  * Posts an image story.
3866
3850
  * @param data data url string `data:[<MIME-type>][;charset=<encoding>][;base64],<data>`
@@ -3873,15 +3857,7 @@ class Client {
3873
3857
  });
3874
3858
  }
3875
3859
  /**
3876
- * @deprecated
3877
- *
3878
- * :::danger
3879
- *
3880
- * Status features are broken for now. Please join our discord community for updates.
3881
- *
3882
- * :::
3883
- *
3884
- * [REQUIRES A VIDEO STORY LICENSE-KEY](https://gum.co/open-wa)
3860
+ * {@license:restricted@}
3885
3861
  *
3886
3862
  * Posts a video story.
3887
3863
  * @param data data url string `data:[<MIME-type>][;charset=<encoding>][;base64],<data>`
@@ -3907,7 +3883,6 @@ class Client {
3907
3883
  });
3908
3884
  }
3909
3885
  /**
3910
- * @deprecated
3911
3886
  * Alias for deleteStory
3912
3887
  */
3913
3888
  deleteStatus(statusesToDelete) {
@@ -3927,7 +3902,6 @@ class Client {
3927
3902
  });
3928
3903
  }
3929
3904
  /**
3930
- * @deprecated
3931
3905
  * Alias for deleteStory
3932
3906
  */
3933
3907
  deleteAllStatus() {
@@ -3948,7 +3922,6 @@ class Client {
3948
3922
  });
3949
3923
  }
3950
3924
  /**
3951
- * @deprecated
3952
3925
  * Alias for deleteStory
3953
3926
  */
3954
3927
  getMyStatusArray() {
@@ -237,7 +237,19 @@ exports.optionList = [{
237
237
  {
238
238
  name: 'tunnel',
239
239
  type: Boolean,
240
- description: "Expose a tunnel to your EASY API session - this is for testing and it is unsecured."
240
+ description: "Expose a tunnel to your EASY API session - this is for testing and it is unsecured. By default it will use a random cloudflare tunnel URL. Make sure you have cloudflared installed and running."
241
+ },
242
+ {
243
+ name: 'cf-tunnel-host-domain',
244
+ type: String,
245
+ typeLabel: '{yellow {underline "mycool.site"}}',
246
+ description: "If you have a domain set up in a cloudflare account and have run cloudflared login on your machine, you can use this to expose the tunnel on your own domain. For example, if you set --cf-tunnel-host-domain mycool.site, the tunnel will be exposed on https://session_id_owa.mycool.site"
247
+ },
248
+ {
249
+ name: 'cf-tunnel-namespace',
250
+ type: String,
251
+ typeLabel: '{yellow {underline "owa"}}',
252
+ description: "You can set a sub-subdomain namespace on which the tunnel will be exposed. Needs to be set in conjunction with --tunnel & --cf-tunnel-host-domain. For example, if you set --cf-tunnel-namespace owa, the tunnel will be exposed on https://session_id.owa.mycool.site"
241
253
  },
242
254
  {
243
255
  name: 'pm2',
package/dist/cli/index.js CHANGED
@@ -201,7 +201,7 @@ function start() {
201
201
  });
202
202
  if (cliConfig.tunnel) {
203
203
  spinner.info(`\n• Setting up external tunnel`);
204
- const tunnelUrl = yield (0, server_1.setupTunnel)(cliConfig, yield client.getTunnelCode(), PORT);
204
+ const tunnelUrl = yield (0, server_1.setupTunnel)(cliConfig, PORT);
205
205
  spinner.succeed(`\n\t${(0, terminal_link_1.default)('External address', tunnelUrl)}`);
206
206
  }
207
207
  const apiDocsUrl = cliConfig.apiHost ? `${cliConfig.apiHost}/api-docs/ ` : `${cliConfig.host.includes('http') ? '' : 'http://'}${cliConfig.host}:${PORT}/api-docs/ `;
@@ -51,6 +51,8 @@ const chatwootMiddleware = (cliConfig, client) => {
51
51
  var _a, _b, _c, _d;
52
52
  const promises = [];
53
53
  const { body } = req;
54
+ if (body.source_id)
55
+ return;
54
56
  if (!body)
55
57
  return;
56
58
  if (body.event == "conversation_status_changed" && body.status == "resolved") {
@@ -407,7 +409,7 @@ class ChatwootClient {
407
409
  try {
408
410
  const { data } = yield this.cwReq('post', `contacts`, {
409
411
  "identifier": contact.id,
410
- "name": contact.formattedName || contact.id,
412
+ "name": contact.formattedName || contact.name || contact.shortName || contact.id,
411
413
  "phone_number": `+${contact.id.replace('@c.us', '')}`,
412
414
  "avatar_url": contact.profilePicThumbObj.eurl,
413
415
  "custom_attributes": Object.assign({ "wa:number": `${contact.id.replace('@c.us', '')}` }, contact)
@@ -440,7 +442,9 @@ class ChatwootClient {
440
442
  content,
441
443
  "message_type": message.fromMe ? "outgoing" : "incoming",
442
444
  "private": false,
443
- echo_id: message.id
445
+ echo_id: message.id,
446
+ source_id: message.id,
447
+ "content_attributes": message
444
448
  });
445
449
  return data;
446
450
  }
@@ -492,8 +496,8 @@ class ChatwootClient {
492
496
  contactReg[message.chatId] = contact.id;
493
497
  }
494
498
  else {
495
- //create the contact
496
- contactReg[message.chatId] = (yield this.createContact(message.sender)).id;
499
+ //create the contact (have to use chat.contact because it may be triggered by an agent doing an outgoing message)
500
+ contactReg[message.chatId] = (yield this.createContact(message.chat.contact)).id;
497
501
  }
498
502
  }
499
503
  if (!convoReg[message.chatId]) {
@@ -0,0 +1,6 @@
1
+ export declare const createCustomDomainTunnel: (cliConfig: any, PORT: number) => Promise<{
2
+ url: string;
3
+ connections: Promise<any>[];
4
+ child: any;
5
+ stop: () => Promise<void>;
6
+ }>;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createCustomDomainTunnel = void 0;
13
+ const cloudflared_1 = require("cloudflared");
14
+ const __1 = require("../..");
15
+ const createCustomDomainTunnel = (cliConfig, PORT) => __awaiter(void 0, void 0, void 0, function* () {
16
+ const { cfTunnelHostDomain, sessionId, cfTunnelNamespace } = cliConfig;
17
+ const sessionName = sessionId.replace(/[^A-Z0-9]/ig, "_").toLowerCase();
18
+ const tunnelName = `_owa_${sessionName}`;
19
+ const FQDN = `${sessionName}${cfTunnelNamespace ? `.${cfTunnelNamespace}` : `_owa`}.${cfTunnelHostDomain}`;
20
+ const hostname = `https://${FQDN}`;
21
+ const target = `http://localhost:${PORT}`;
22
+ const logData = (data) => __1.log.info(`CLOUDFLARE TUNNEL: ${typeof data === "object" ? JSON.stringify(data, null, 2) : data}`);
23
+ // simlpe helper function to convert child proc to a promise and log the output
24
+ const cfp = (child) => {
25
+ return new Promise((resolve, reject) => {
26
+ var _a, _b;
27
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', logData);
28
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', logData);
29
+ child.on('error', reject);
30
+ child.on('exit', (code) => {
31
+ if (code === 0) {
32
+ resolve(true);
33
+ }
34
+ else {
35
+ reject(`Exit code: ${code}`);
36
+ }
37
+ });
38
+ });
39
+ };
40
+ __1.log.info(`Checking if tunnel ${tunnelName} exists...`);
41
+ const tunnelExists = yield new Promise((resolve) => {
42
+ const check = (data) => {
43
+ logData(data.toString());
44
+ return resolve(!data.toString().includes("error"));
45
+ };
46
+ const { child } = (0, cloudflared_1.tunnel)({ "info": tunnelName });
47
+ child.stdout.once('data', check);
48
+ child.stderr.once('data', check);
49
+ });
50
+ if (!tunnelExists) {
51
+ __1.log.info("Tunnel does not exist, creating...");
52
+ yield cfp((0, cloudflared_1.tunnel)({ "create": tunnelName }).child);
53
+ }
54
+ __1.log.info(`Routing traffic to the tunnel via URL ${FQDN}...`);
55
+ yield cfp((0, cloudflared_1.tunnel)({ "route": "dns", "--overwrite-dns": null, [tunnelName]: FQDN }).child);
56
+ const { connections, child, stop } = (0, cloudflared_1.tunnel)({
57
+ "--url": target,
58
+ "--hostname": hostname,
59
+ "run": tunnelName
60
+ });
61
+ child.stdout.on('data', logData);
62
+ // wait for the all 4 connections to be established
63
+ const conns = yield Promise.all(connections);
64
+ // show the connections
65
+ __1.log.info("Connections Ready!", conns);
66
+ return {
67
+ url: hostname,
68
+ connections,
69
+ child,
70
+ stop: () => __awaiter(void 0, void 0, void 0, function* () {
71
+ stop();
72
+ yield cfp((0, cloudflared_1.tunnel)({ "delete": tunnelName }).child);
73
+ })
74
+ };
75
+ });
76
+ exports.createCustomDomainTunnel = createCustomDomainTunnel;
@@ -17,7 +17,7 @@ export declare const setupMetaProcessMiddleware: (client: Client, cliConfig: any
17
17
  export declare const getCommands: () => any;
18
18
  export declare const listListeners: () => string[];
19
19
  export declare const setupMediaMiddleware: () => void;
20
- export declare const setupTunnel: (cliConfig: any, tunnelCode: string, PORT: number) => Promise<string>;
20
+ export declare const setupTunnel: (cliConfig: any, PORT: number) => Promise<string>;
21
21
  export declare const setupTwilioCompatibleWebhook: (cliConfig: cliFlags, client: Client) => void;
22
22
  export declare const setupChatwoot: (cliConfig: cliFlags, client: Client) => void;
23
23
  export declare const setupBotPressHandler: (cliConfig: cliFlags, client: Client) => void;
@@ -52,11 +52,13 @@ const xmlbuilder2_1 = require("xmlbuilder2");
52
52
  const chatwoot_1 = require("./integrations/chatwoot");
53
53
  const express_ipfilter_1 = require("express-ipfilter");
54
54
  const helmet_1 = __importDefault(require("helmet"));
55
- const localtunnel_1 = __importDefault(require("localtunnel"));
55
+ const cloudflared_1 = require("cloudflared");
56
56
  const child_process_1 = require("child_process");
57
+ const cloudflare_1 = require("./integrations/cloudflare");
57
58
  exports.app = (0, express_1.default)();
58
59
  exports.server = http_1.default.createServer(exports.app);
59
- let tunnel;
60
+ // will be used to clean up cloudflared tunnel
61
+ let stop;
60
62
  const trimChatId = (chatId) => chatId.replace("@c.us", "").replace("@g.us", "");
61
63
  const socketListenerCallbacks = {};
62
64
  // const existingListeners = () => Object.keys(Object.keys(socketListenerCallbacks).flatMap(id=>Object.keys(socketListenerCallbacks[id])).reduce((acc,curr)=>{acc[curr]=true;return acc},{}))
@@ -262,8 +264,8 @@ const setupMetaProcessMiddleware = (client, cliConfig) => {
262
264
  closing = true;
263
265
  yield client.kill("API_KILL");
264
266
  __1.log.info("Waiting for maximum ");
265
- if (tunnel && tunnel.close && typeof tunnel.close === 'function')
266
- tunnel.close();
267
+ if (stop && typeof stop === 'function')
268
+ stop();
267
269
  yield Promise.race([
268
270
  new Promise((resolve) => exports.server.close(() => {
269
271
  console.log('Server closed');
@@ -319,14 +321,14 @@ const setupMediaMiddleware = () => {
319
321
  exports.app.use("/media", express_1.default.static('media'));
320
322
  };
321
323
  exports.setupMediaMiddleware = setupMediaMiddleware;
322
- const setupTunnel = (cliConfig, tunnelCode, PORT) => __awaiter(void 0, void 0, void 0, function* () {
323
- tunnel = yield (0, localtunnel_1.default)({
324
- port: PORT,
325
- host: process.env.WA_TUNNEL_SERVER || "https://public.openwa.cloud",
326
- subdomain: tunnelCode
327
- });
328
- cliConfig.apiHost = cliConfig.tunnel = tunnel.url;
329
- return tunnel.url;
324
+ const setupTunnel = (cliConfig, PORT) => __awaiter(void 0, void 0, void 0, function* () {
325
+ const cfT = cliConfig.cfTunnelHostDomain ? yield (0, cloudflare_1.createCustomDomainTunnel)(cliConfig, PORT) : (0, cloudflared_1.tunnel)({ "--url": `localhost:${PORT}` });
326
+ stop = cfT.stop;
327
+ const url = yield cfT.url;
328
+ const conns = yield Promise.all(cfT.connections);
329
+ __1.log.info(`Connections Ready! ${conns}`);
330
+ cliConfig.apiHost = cliConfig.tunnel = url;
331
+ return url;
330
332
  });
331
333
  exports.setupTunnel = setupTunnel;
332
334
  const setupTwilioCompatibleWebhook = (cliConfig, client) => {
@@ -323,6 +323,7 @@ function create(config = {}) {
323
323
  }
324
324
  if (config.logInternalEvents)
325
325
  yield waPage.evaluate("debugEvents=true");
326
+ yield waPage.evaluate("window.critlis=true");
326
327
  const tI = yield (0, tools_1.timePromise)(() => (0, init_patch_1.injectInternalEventHandler)(waPage));
327
328
  logging_1.log.info(`Injected internal event handler: ${tI} ms`);
328
329
  if (attemptingReauth) {
@@ -47,6 +47,26 @@ const sensitiveKeys = [
47
47
  /token/i,
48
48
  /api[-._]?key/i,
49
49
  ];
50
+ const getCircularReplacer = () => {
51
+ const seen = new WeakSet();
52
+ return (_key, value) => {
53
+ if (typeof value === "object" && value !== null) {
54
+ if (seen.has(value)) {
55
+ return "[Circular]";
56
+ }
57
+ seen.add(value);
58
+ }
59
+ return value;
60
+ };
61
+ };
62
+ const k = (obj) => {
63
+ try {
64
+ return (0, full_1.klona)(obj);
65
+ }
66
+ catch (error) {
67
+ return (0, full_1.klona)(JSON.parse(JSON.stringify(obj, getCircularReplacer())));
68
+ }
69
+ };
50
70
  function isSensitiveKey(keyStr) {
51
71
  if (keyStr && typeof keyStr == "string") {
52
72
  return sensitiveKeys.some(regex => regex.test(keyStr));
@@ -63,7 +83,7 @@ function redactObject(obj) {
63
83
  });
64
84
  }
65
85
  function redact(obj) {
66
- const copy = (0, full_1.klona)(obj); // Making a deep copy to prevent side effects
86
+ const copy = k(obj); // Making a deep copy to prevent side effects
67
87
  redactObject(copy);
68
88
  const splat = copy[Symbol.for("splat")];
69
89
  redactObject(splat); // Specifically redact splat Symbol
@@ -74,7 +94,7 @@ function truncate(str, n) {
74
94
  }
75
95
  const formatRedact = winston.format(redact);
76
96
  const stringSaver = winston.format((info) => {
77
- const copy = (0, full_1.klona)(info);
97
+ const copy = k(info);
78
98
  const splat = copy[Symbol.for("splat")];
79
99
  if (splat) {
80
100
  copy.message = `${copy.message} ${splat.filter((x) => typeof x !== 'object').join(' ')}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-wa/wa-automate",
3
- "version": "4.67.0",
3
+ "version": "4.68.0",
4
4
  "licenseCheckUrl": "https://funcs.openwa.dev/license-check",
5
5
  "brokenMethodReportUrl": "https://funcs.openwa.dev/report-bm",
6
6
  "patches": "https://cdn.openwa.dev/patches.json",
@@ -72,7 +72,6 @@
72
72
  "@types/express": "^4.17.11",
73
73
  "@types/fs-extra": "^9.0.11",
74
74
  "@types/line-reader": "0.0.34",
75
- "@types/localtunnel": "^2.0.1",
76
75
  "@types/marked": "^4.0.2",
77
76
  "@types/mime": "^3.0.1",
78
77
  "@types/node": "^18.7.6",
@@ -106,7 +105,7 @@
106
105
  "dependencies": {
107
106
  "@brillout/import": "^0.2.1",
108
107
  "@discordjs/collection": "0.8.0",
109
- "@open-wa/wa-automate-socket-client": "*",
108
+ "@open-wa/wa-automate-socket-client": "^3.3.0",
110
109
  "@open-wa/wa-decrypt": "^4.3.1",
111
110
  "atob": "^2.1.2",
112
111
  "aws4": "^1.11.0",
@@ -116,6 +115,7 @@
116
115
  "change-case": "^4.1.2",
117
116
  "chokidar": "^3.5.3",
118
117
  "chrome-launcher": "^0.15.0",
118
+ "cloudflared": "^0.5.1",
119
119
  "command-exists": "^1.2.9",
120
120
  "command-line-usage": "^6.1.1",
121
121
  "cors": "^2.8.5",
@@ -138,7 +138,6 @@
138
138
  "is-url-superb": "^5.0.0",
139
139
  "json5": "^2.2.0",
140
140
  "klona": "^2.0.5",
141
- "localtunnel": "^2.0.2",
142
141
  "lodash.uniq": "^4.5.0",
143
142
  "meow": "^9.0.0",
144
143
  "mime": "^3.0.0",