'use strict';
33 |
34 | const Chat = require('./Chat');
35 |
36 | /**
37 | * Represents a Private Chat on WhatsApp
38 | * @extends {Chat}
39 | */
40 | class PrivateChat extends Chat {
41 |
42 | }
43 |
44 | module.exports = PrivateChat;
45 | 'use strict';
33 |
34 | const Chat = require('./Chat');
35 |
36 | /**
37 | * Represents a Private Chat on WhatsApp
38 | * @extends {Chat}
39 | */
40 | class PrivateChat extends Chat {
41 |
42 | }
43 |
44 | module.exports = PrivateChat;
45 | 'use strict';
33 |
34 | const Contact = require('./Contact');
35 |
36 | /**
37 | * Represents a Private Contact on WhatsApp
38 | * @extends {Contact}
39 | */
40 | class PrivateContact extends Contact {
41 |
42 | }
43 |
44 | module.exports = PrivateContact;
45 | 'use strict';
33 |
34 | const BaseAuthStrategy = require('./BaseAuthStrategy');
35 |
36 | /**
37 | * No session restoring functionality
38 | * Will need to authenticate via QR code every time
39 | */
40 | class NoAuth extends BaseAuthStrategy { }
41 |
42 |
43 | module.exports = NoAuth;
44 | 'use strict';
33 |
34 | /**
35 | * Represents a WhatsApp data structure
36 | */
37 | class Base {
38 | constructor(client) {
39 | /**
40 | * The client that instantiated this
41 | * @readonly
42 | */
43 | Object.defineProperty(this, 'client', { value: client });
44 | }
45 |
46 | _clone() {
47 | return Object.assign(Object.create(this), this);
48 | }
49 |
50 | _patch(data) { return data; }
51 | }
52 |
53 | module.exports = Base;
54 | 'use strict';
33 |
34 | const Contact = require('./Contact');
35 |
36 | /**
37 | * Represents a Business Contact on WhatsApp
38 | * @extends {Contact}
39 | */
40 | class BusinessContact extends Contact {
41 | _patch(data) {
42 | /**
43 | * The contact's business profile
44 | */
45 | this.businessProfile = data.businessProfile;
46 |
47 | return super._patch(data);
48 | }
49 |
50 | }
51 |
52 | module.exports = BusinessContact;
53 | Source: structures/
Represents a WhatsApp data structure
32 |'use strict';
33 |
34 | /**
35 | * Base class which all authentication strategies extend
36 | */
37 | class BaseAuthStrategy {
38 | constructor() {}
39 | setup(client) {
40 | this.client = client;
41 | }
42 | async beforeBrowserInitialized() {}
43 | async afterBrowserInitialized() {}
44 | async onAuthenticationNeeded() {
45 | return {
46 | failed: false,
47 | restart: false,
48 | failureEventPayload: undefined
49 | };
50 | }
51 | async getAuthEventPayload() {}
52 | async logout() {}
53 | }
54 |
55 | module.exports = BaseAuthStrategy;
56 | Source: authStrategies/
No session restoring functionality 32 | Will need to authenticate via QR code every time
33 |const Base = require('./Base');
33 |
34 | class ProductMetadata extends Base {
35 | constructor(client, data) {
36 | super(client);
37 |
38 | if (data) this._patch(data);
39 | }
40 |
41 | _patch(data) {
42 | /** Product ID */
43 | this.id = data.id;
44 | /** Retailer ID */
45 | this.retailer_id = data.retailer_id;
46 | /** Product Name */
47 | this.name = data.name;
48 | /** Product Description */
49 | this.description = data.description;
50 |
51 | return super._patch(data);
52 | }
53 |
54 | }
55 |
56 | module.exports = ProductMetadata;
57 | Source: authStrategies/
Base class which all authentication strategies extend
32 |'use strict';
33 |
34 | /**
35 | * Location information
36 | */
37 | class Location {
38 | /**
39 | * @param {number} latitude
40 | * @param {number} longitude
41 | * @param {?string} description
42 | */
43 | constructor(latitude, longitude, description) {
44 | /**
45 | * Location latitude
46 | * @type {number}
47 | */
48 | this.latitude = latitude;
49 |
50 | /**
51 | * Location longitude
52 | * @type {number}
53 | */
54 | this.longitude = longitude;
55 |
56 | /**
57 | * Name for the location
58 | * @type {?string}
59 | */
60 | this.description = description;
61 | }
62 | }
63 |
64 | module.exports = Location;
65 | 'use strict';
33 |
34 | const Base = require('./Base');
35 | // eslint-disable-next-line no-unused-vars
36 | const Chat = require('./Chat');
37 |
38 | /**
39 | * WhatsApp Business Label information
40 | */
41 | class Label extends Base {
42 | /**
43 | * @param {Base} client
44 | * @param {object} labelData
45 | */
46 | constructor(client, labelData){
47 | super(client);
48 |
49 | if(labelData) this._patch(labelData);
50 | }
51 |
52 | _patch(labelData){
53 | /**
54 | * Label ID
55 | * @type {string}
56 | */
57 | this.id = labelData.id;
58 |
59 | /**
60 | * Label name
61 | * @type {string}
62 | */
63 | this.name = labelData.name;
64 |
65 | /**
66 | * Label hex color
67 | * @type {string}
68 | */
69 | this.hexColor = labelData.hexColor;
70 | }
71 | /**
72 | * Get all chats that have been assigned this Label
73 | * @returns {Promise<Array<Chat>>}
74 | */
75 | async getChats(){
76 | return this.client.getChatsByLabelId(this.id);
77 | }
78 |
79 | }
80 |
81 | module.exports = Label;
82 | 'use strict';
33 |
34 | const Base = require('./Base');
35 | const Product = require('./Product');
36 |
37 | /**
38 | * Represents a Order on WhatsApp
39 | * @extends {Base}
40 | */
41 | class Order extends Base {
42 | constructor(client, data) {
43 | super(client);
44 |
45 | if (data) this._patch(data);
46 | }
47 |
48 | _patch(data) {
49 | /**
50 | * List of products
51 | * @type {Array<Product>}
52 | */
53 | if (data.products) {
54 | this.products = data.products.map(product => new Product(this.client, product));
55 | }
56 | /**
57 | * Order Subtotal
58 | * @type {string}
59 | */
60 | this.subtotal = data.subtotal;
61 | /**
62 | * Order Total
63 | * @type {string}
64 | */
65 | this.total = data.total;
66 | /**
67 | * Order Currency
68 | * @type {string}
69 | */
70 | this.currency = data.currency;
71 | /**
72 | * Order Created At
73 | * @type {number}
74 | */
75 | this.createdAt = data.createdAt;
76 |
77 | return super._patch(data);
78 | }
79 |
80 |
81 | }
82 |
83 | module.exports = Order;
84 | 'use strict';
33 |
34 | const Base = require('./Base');
35 |
36 | /**
37 | * Represents a Call on WhatsApp
38 | * @extends {Base}
39 | */
40 | class Call extends Base {
41 | constructor(client, data) {
42 | super(client);
43 |
44 | if (data) this._patch(data);
45 | }
46 |
47 | _patch(data) {
48 | /**
49 | * Call ID
50 | * @type {string}
51 | */
52 | this.id = data.id;
53 | /**
54 | * From
55 | * @type {string}
56 | */
57 | this.from = data.peerJid;
58 | /**
59 | * Unix timestamp for when the call was created
60 | * @type {number}
61 | */
62 | this.timestamp = data.offerTime;
63 | /**
64 | * Is video
65 | * @type {boolean}
66 | */
67 | this.isVideo = data.isVideo;
68 | /**
69 | * Is Group
70 | * @type {boolean}
71 | */
72 | this.isGroup = data.isGroup;
73 | /**
74 | * Indicates if the call was sent by the current user
75 | * @type {boolean}
76 | */
77 | this.fromMe = data.outgoing;
78 | /**
79 | * Indicates if the call can be handled in waweb
80 | * @type {boolean}
81 | */
82 | this.canHandleLocally = data.canHandleLocally;
83 | /**
84 | * Indicates if the call Should be handled in waweb
85 | * @type {boolean}
86 | */
87 | this.webClientShouldHandle = data.webClientShouldHandle;
88 | /**
89 | * Object with participants
90 | * @type {object}
91 | */
92 | this.participants = data.participants;
93 |
94 | return super._patch(data);
95 | }
96 |
97 | }
98 |
99 | module.exports = Call;
100 | 'use strict';
33 |
34 | const Base = require('./Base');
35 | const ProductMetadata = require('./ProductMetadata');
36 |
37 | /**
38 | * Represents a Product on WhatsAppBusiness
39 | * @extends {Base}
40 | */
41 | class Product extends Base {
42 | constructor(client, data) {
43 | super(client);
44 |
45 | if (data) this._patch(data);
46 | }
47 |
48 | _patch(data) {
49 | /**
50 | * Product ID
51 | * @type {string}
52 | */
53 | this.id = data.id;
54 | /**
55 | * Price
56 | * @type {string}
57 | */
58 | this.price = data.price ? data.price : '';
59 | /**
60 | * Product Thumbnail
61 | * @type {string}
62 | */
63 | this.thumbnailUrl = data.thumbnailUrl;
64 | /**
65 | * Currency
66 | * @type {string}
67 | */
68 | this.currency = data.currency;
69 | /**
70 | * Product Name
71 | * @type {string}
72 | */
73 | this.name = data.name;
74 | /**
75 | * Product Quantity
76 | * @type {number}
77 | */
78 | this.quantity = data.quantity;
79 | /** Product metadata */
80 | this.data = null;
81 | return super._patch(data);
82 | }
83 |
84 | async getData() {
85 | if (this.data === null) {
86 | let result = await this.client.pupPage.evaluate((productId) => {
87 | return window.WWebJS.getProductMetadata(productId);
88 | }, this.id);
89 | if (!result) {
90 | this.data = undefined;
91 | } else {
92 | this.data = new ProductMetadata(this.client, result);
93 | }
94 | }
95 | return this.data;
96 | }
97 | }
98 |
99 | module.exports = Product;
100 | 'use strict';
33 |
34 | const path = require('path');
35 | const fs = require('fs');
36 | const BaseAuthStrategy = require('./BaseAuthStrategy');
37 |
38 | /**
39 | * Local directory-based authentication
40 | * @param {object} options - options
41 | * @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
42 | * @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
43 | */
44 | class LocalAuth extends BaseAuthStrategy {
45 | constructor({ clientId, dataPath }={}) {
46 | super();
47 |
48 | const idRegex = /^[-_\w]+$/i;
49 | if(clientId && !idRegex.test(clientId)) {
50 | throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
51 | }
52 |
53 | this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
54 | this.clientId = clientId;
55 | }
56 |
57 | async beforeBrowserInitialized() {
58 | const puppeteerOpts = this.client.options.puppeteer;
59 | const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
60 | const dirPath = path.join(this.dataPath, sessionDirName);
61 |
62 | if(puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
63 | throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
64 | }
65 |
66 | fs.mkdirSync(dirPath, { recursive: true });
67 |
68 | this.client.options.puppeteer = {
69 | ...puppeteerOpts,
70 | userDataDir: dirPath
71 | };
72 |
73 | this.userDataDir = dirPath;
74 | }
75 |
76 | async logout() {
77 | if (this.userDataDir) {
78 | return (fs.rmSync ? fs.rmSync : fs.rmdirSync).call(this, this.userDataDir, { recursive: true });
79 | }
80 | }
81 |
82 | }
83 |
84 | module.exports = LocalAuth;
85 | const Base = require('./Base');
33 |
34 | class Payment extends Base {
35 | constructor(client, data) {
36 | super(client);
37 |
38 | if (data) this._patch(data);
39 | }
40 |
41 | _patch(data) {
42 | /**
43 | * The payment Id
44 | * @type {object}
45 | */
46 | this.id = data.id;
47 |
48 | /**
49 | * The payment currency
50 | * @type {string}
51 | */
52 | this.paymentCurrency = data.paymentCurrency;
53 |
54 | /**
55 | * The payment ammount ( R$ 1.00 = 1000 )
56 | * @type {number}
57 | */
58 | this.paymentAmount1000 = data.paymentAmount1000;
59 |
60 | /**
61 | * The payment receiver
62 | * @type {object}
63 | */
64 | this.paymentMessageReceiverJid = data.paymentMessageReceiverJid;
65 |
66 | /**
67 | * The payment transaction timestamp
68 | * @type {number}
69 | */
70 | this.paymentTransactionTimestamp = data.paymentTransactionTimestamp;
71 |
72 | /**
73 | * The paymentStatus
74 | *
75 | * Possible Status
76 | * 0:UNKNOWN_STATUS
77 | * 1:PROCESSING
78 | * 2:SENT
79 | * 3:NEED_TO_ACCEPT
80 | * 4:COMPLETE
81 | * 5:COULD_NOT_COMPLETE
82 | * 6:REFUNDED
83 | * 7:EXPIRED
84 | * 8:REJECTED
85 | * 9:CANCELLED
86 | * 10:WAITING_FOR_PAYER
87 | * 11:WAITING
88 | *
89 | * @type {number}
90 | */
91 | this.paymentStatus = data.paymentStatus;
92 |
93 | /**
94 | * Integer that represents the payment Text
95 | * @type {number}
96 | */
97 | this.paymentTxnStatus = data.paymentTxnStatus;
98 |
99 | /**
100 | * The note sent with the payment
101 | * @type {string}
102 | */
103 | this.paymentNote = !data.paymentNoteMsg ? undefined : data.paymentNoteMsg.body ? data.paymentNoteMsg.body : undefined ;
104 |
105 | return super._patch(data);
106 | }
107 |
108 | }
109 |
110 | module.exports = Payment;
111 |
112 | 'use strict';
33 |
34 | const Base = require('./Base');
35 |
36 | /**
37 | * Current connection information
38 | * @extends {Base}
39 | */
40 | class ClientInfo extends Base {
41 | constructor(client, data) {
42 | super(client);
43 |
44 | if (data) this._patch(data);
45 | }
46 |
47 | _patch(data) {
48 | /**
49 | * Name configured to be shown in push notifications
50 | * @type {string}
51 | */
52 | this.pushname = data.pushname;
53 |
54 | /**
55 | * Current user ID
56 | * @type {object}
57 | */
58 | this.wid = data.wid;
59 |
60 | /**
61 | * @type {object}
62 | * @deprecated Use .wid instead
63 | */
64 | this.me = data.wid;
65 |
66 | /**
67 | * Information about the phone this client is connected to. Not available in multi-device.
68 | * @type {object}
69 | * @property {string} wa_version WhatsApp Version running on the phone
70 | * @property {string} os_version OS Version running on the phone (iOS or Android version)
71 | * @property {string} device_manufacturer Device manufacturer
72 | * @property {string} device_model Device model
73 | * @property {string} os_build_number OS build number
74 | * @deprecated
75 | */
76 | this.phone = data.phone;
77 |
78 | /**
79 | * Platform WhatsApp is running on
80 | * @type {string}
81 | */
82 | this.platform = data.platform;
83 |
84 | return super._patch(data);
85 | }
86 |
87 | /**
88 | * Get current battery percentage and charging status for the attached device
89 | * @returns {object} batteryStatus
90 | * @returns {number} batteryStatus.battery - The current battery percentage
91 | * @returns {boolean} batteryStatus.plugged - Indicates if the phone is plugged in (true) or not (false)
92 | * @deprecated
93 | */
94 | async getBatteryStatus() {
95 | return await this.client.pupPage.evaluate(() => {
96 | const { battery, plugged } = window.Store.Conn;
97 | return { battery, plugged };
98 | });
99 | }
100 | }
101 |
102 | module.exports = ClientInfo;
103 | Source: structures/
Represents a Order on WhatsApp
32 |Order Created At
78 |Order Currency
83 |Order Subtotal
88 |Order Total
93 |'use strict';
33 |
34 | const MessageMedia = require('./MessageMedia');
35 | const Util = require('../util/Util');
36 |
37 | /**
38 | * Button spec used in Buttons constructor
39 | * @typedef {Object} ButtonSpec
40 | * @property {string=} id - Custom ID to set on the button. A random one will be generated if one is not passed.
41 | * @property {string} body - The text to show on the button.
42 | */
43 |
44 | /**
45 | * @typedef {Object} FormattedButtonSpec
46 | * @property {string} buttonId
47 | * @property {number} type
48 | * @property {Object} buttonText
49 | */
50 |
51 | /**
52 | * Message type buttons
53 | */
54 | class Buttons {
55 | /**
56 | * @param {string|MessageMedia} body
57 | * @param {ButtonSpec[]} buttons - See {@link ButtonSpec}
58 | * @param {string?} title
59 | * @param {string?} footer
60 | */
61 | constructor(body, buttons, title, footer) {
62 | /**
63 | * Message body
64 | * @type {string|MessageMedia}
65 | */
66 | this.body = body;
67 |
68 | /**
69 | * title of message
70 | * @type {string}
71 | */
72 | this.title = title;
73 |
74 | /**
75 | * footer of message
76 | * @type {string}
77 | */
78 | this.footer = footer;
79 |
80 | if (body instanceof MessageMedia) {
81 | this.type = 'media';
82 | this.title = '';
83 | }else{
84 | this.type = 'chat';
85 | }
86 |
87 | /**
88 | * buttons of message
89 | * @type {FormattedButtonSpec[]}
90 | */
91 | this.buttons = this._format(buttons);
92 | if(!this.buttons.length){ throw '[BT01] No buttons';}
93 |
94 | }
95 |
96 | /**
97 | * Creates button array from simple array
98 | * @param {ButtonSpec[]} buttons
99 | * @returns {FormattedButtonSpec[]}
100 | * @example
101 | * Input: [{id:'customId',body:'button1'},{body:'button2'},{body:'button3'},{body:'button4'}]
102 | * Returns: [{ buttonId:'customId',buttonText:{'displayText':'button1'},type: 1 },{buttonId:'n3XKsL',buttonText:{'displayText':'button2'},type:1},{buttonId:'NDJk0a',buttonText:{'displayText':'button3'},type:1}]
103 | */
104 | _format(buttons){
105 | buttons = buttons.slice(0,3); // phone users can only see 3 buttons, so lets limit this
106 | return buttons.map((btn) => {
107 | return {'buttonId':btn.id ? String(btn.id) : Util.generateHash(6),'buttonText':{'displayText':btn.body},'type':1};
108 | });
109 | }
110 |
111 | }
112 |
113 | module.exports = Buttons;
114 | 'use strict';
33 |
34 | const Util = require('../util/Util');
35 |
36 | /**
37 | * Message type List
38 | */
39 | class List {
40 | /**
41 | * @param {string} body
42 | * @param {string} buttonText
43 | * @param {Array<any>} sections
44 | * @param {string?} title
45 | * @param {string?} footer
46 | */
47 | constructor(body, buttonText, sections, title, footer) {
48 | /**
49 | * Message body
50 | * @type {string}
51 | */
52 | this.description = body;
53 |
54 | /**
55 | * List button text
56 | * @type {string}
57 | */
58 | this.buttonText = buttonText;
59 |
60 | /**
61 | * title of message
62 | * @type {string}
63 | */
64 | this.title = title;
65 |
66 |
67 | /**
68 | * footer of message
69 | * @type {string}
70 | */
71 | this.footer = footer;
72 |
73 | /**
74 | * sections of message
75 | * @type {Array<any>}
76 | */
77 | this.sections = this._format(sections);
78 |
79 | }
80 |
81 | /**
82 | * Creates section array from simple array
83 | * @param {Array<any>} sections
84 | * @returns {Array<any>}
85 | * @example
86 | * Input: [{title:'sectionTitle',rows:[{id:'customId', title:'ListItem2', description: 'desc'},{title:'ListItem2'}]}}]
87 | * Returns: [{'title':'sectionTitle','rows':[{'rowId':'customId','title':'ListItem1','description':'desc'},{'rowId':'oGSRoD','title':'ListItem2','description':''}]}]
88 | */
89 | _format(sections){
90 | if(!sections.length){throw '[LT02] List without sections';}
91 | if(sections.length > 1 && sections.filter(s => typeof s.title == 'undefined').length > 1){throw '[LT05] You can\'t have more than one empty title.';}
92 | return sections.map( (section) =>{
93 | if(!section.rows.length){throw '[LT03] Section without rows';}
94 | return {
95 | title: section.title ? section.title : undefined,
96 | rows: section.rows.map( (row) => {
97 | if(!row.title){throw '[LT04] Row without title';}
98 | return {
99 | rowId: row.id ? row.id : Util.generateHash(6),
100 | title: row.title,
101 | description: row.description ? row.description : ''
102 | };
103 | })
104 | };
105 | });
106 | }
107 |
108 | }
109 |
110 | module.exports = List;
111 |
112 | 'use strict';
33 |
34 | const BaseAuthStrategy = require('./BaseAuthStrategy');
35 |
36 | /**
37 | * Legacy session auth strategy
38 | * Not compatible with multi-device accounts.
39 | * @param {object} options - options
40 | * @param {string} options.restartOnAuthFail - Restart client with a new session (i.e. use null 'session' var) if authentication fails
41 | * @param {object} options.session - Whatsapp session to restore. If not set, will start a new session
42 | * @param {string} options.session.WABrowserId
43 | * @param {string} options.session.WASecretBundle
44 | * @param {string} options.session.WAToken1
45 | * @param {string} options.session.WAToken2
46 | */
47 | class LegacySessionAuth extends BaseAuthStrategy {
48 | constructor({ session, restartOnAuthFail }={}) {
49 | super();
50 | this.session = session;
51 | this.restartOnAuthFail = restartOnAuthFail;
52 | }
53 |
54 | async afterBrowserInitialized() {
55 | if(this.session) {
56 | await this.client.pupPage.evaluateOnNewDocument(session => {
57 | if (document.referrer === 'https://whatsapp.com/') {
58 | localStorage.clear();
59 | localStorage.setItem('WABrowserId', session.WABrowserId);
60 | localStorage.setItem('WASecretBundle', session.WASecretBundle);
61 | localStorage.setItem('WAToken1', session.WAToken1);
62 | localStorage.setItem('WAToken2', session.WAToken2);
63 | }
64 |
65 | localStorage.setItem('remember-me', 'true');
66 | }, this.session);
67 | }
68 | }
69 |
70 | async onAuthenticationNeeded() {
71 | if(this.session) {
72 | this.session = null;
73 | return {
74 | failed: true,
75 | restart: this.restartOnAuthFail,
76 | failureEventPayload: 'Unable to log in. Are the session details valid?'
77 | };
78 | }
79 |
80 | return { failed: false };
81 | }
82 |
83 | async getAuthEventPayload() {
84 | const isMD = await this.client.pupPage.evaluate(() => {
85 | return window.Store.MDBackend;
86 | });
87 |
88 | if(isMD) throw new Error('Authenticating via JSON session is not supported for MultiDevice-enabled WhatsApp accounts.');
89 |
90 | const localStorage = JSON.parse(await this.client.pupPage.evaluate(() => {
91 | return JSON.stringify(window.localStorage);
92 | }));
93 |
94 | return {
95 | WABrowserId: localStorage.WABrowserId,
96 | WASecretBundle: localStorage.WASecretBundle,
97 | WAToken1: localStorage.WAToken1,
98 | WAToken2: localStorage.WAToken2
99 | };
100 | }
101 | }
102 |
103 | module.exports = LegacySessionAuth;
104 |
105 | 'use strict';
33 |
34 | const Base = require('./Base');
35 |
36 | /**
37 | * Represents a GroupNotification on WhatsApp
38 | * @extends {Base}
39 | */
40 | class GroupNotification extends Base {
41 | constructor(client, data) {
42 | super(client);
43 |
44 | if(data) this._patch(data);
45 | }
46 |
47 | _patch(data) {
48 | /**
49 | * ID that represents the groupNotification
50 | * @type {object}
51 | */
52 | this.id = data.id;
53 |
54 | /**
55 | * Extra content
56 | * @type {string}
57 | */
58 | this.body = data.body || '';
59 |
60 | /**
61 | * GroupNotification type
62 | * @type {GroupNotificationTypes}
63 | */
64 | this.type = data.subtype;
65 |
66 | /**
67 | * Unix timestamp for when the groupNotification was created
68 | * @type {number}
69 | */
70 | this.timestamp = data.t;
71 |
72 | /**
73 | * ID for the Chat that this groupNotification was sent for.
74 | *
75 | * @type {string}
76 | */
77 | this.chatId = typeof (data.id.remote) === 'object' ? data.id.remote._serialized : data.id.remote;
78 |
79 | /**
80 | * ContactId for the user that produced the GroupNotification.
81 | * @type {string}
82 | */
83 | this.author = typeof (data.author) === 'object' ? data.author._serialized : data.author;
84 |
85 | /**
86 | * Contact IDs for the users that were affected by this GroupNotification.
87 | * @type {Array<string>}
88 | */
89 | this.recipientIds = [];
90 |
91 | if (data.recipients) {
92 | this.recipientIds = data.recipients;
93 | }
94 |
95 | return super._patch(data);
96 | }
97 |
98 | /**
99 | * Returns the Chat this groupNotification was sent in
100 | * @returns {Promise<Chat>}
101 | */
102 | getChat() {
103 | return this.client.getChatById(this.chatId);
104 | }
105 |
106 | /**
107 | * Returns the Contact this GroupNotification was produced by
108 | * @returns {Promise<Contact>}
109 | */
110 | getContact() {
111 | return this.client.getContactById(this.author);
112 | }
113 |
114 | /**
115 | * Returns the Contacts affected by this GroupNotification.
116 | * @returns {Promise<Array<Contact>>}
117 | */
118 | async getRecipients() {
119 | return await Promise.all(this.recipientIds.map(async m => await this.client.getContactById(m)));
120 | }
121 |
122 | /**
123 | * Sends a message to the same chat this GroupNotification was produced in.
124 | *
125 | * @param {string|MessageMedia|Location} content
126 | * @param {object} options
127 | * @returns {Promise<Message>}
128 | */
129 | async reply(content, options={}) {
130 | return this.client.sendMessage(this.chatId, content, options);
131 | }
132 |
133 | }
134 |
135 | module.exports = GroupNotification;
136 |
137 | Source: authStrategies/
Local directory-based authentication
32 || Name | 46 |Type | 47 |Optional | 48 |Description | 49 |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
54 | options 55 | |
56 |
57 | 58 | |
59 |
60 | 61 | |
62 |
63 | options 64 |Values in
|
106 |
'use strict';
33 |
34 | /**
35 | * Interface Controller
36 | */
37 | class InterfaceController {
38 |
39 | constructor(props) {
40 | this.pupPage = props.pupPage;
41 | }
42 |
43 | /**
44 | * Opens the Chat Window
45 | * @param {string} chatId ID of the chat window that will be opened
46 | */
47 | async openChatWindow(chatId) {
48 | await this.pupPage.evaluate(async chatId => {
49 | let chatWid = window.Store.WidFactory.createWid(chatId);
50 | let chat = await window.Store.Chat.find(chatWid);
51 | await window.Store.Cmd.openChatAt(chat);
52 | }, chatId);
53 | }
54 |
55 | /**
56 | * Opens the Chat Drawer
57 | * @param {string} chatId ID of the chat drawer that will be opened
58 | */
59 | async openChatDrawer(chatId) {
60 | await this.pupPage.evaluate(async chatId => {
61 | let chat = await window.Store.Chat.get(chatId);
62 | await window.Store.Cmd.openDrawerMid(chat);
63 | }, chatId);
64 | }
65 |
66 | /**
67 | * Opens the Chat Search
68 | * @param {string} chatId ID of the chat search that will be opened
69 | */
70 | async openChatSearch(chatId) {
71 | await this.pupPage.evaluate(async chatId => {
72 | let chat = await window.Store.Chat.get(chatId);
73 | await window.Store.Cmd.chatSearch(chat);
74 | }, chatId);
75 | }
76 |
77 | /**
78 | * Opens or Scrolls the Chat Window to the position of the message
79 | * @param {string} msgId ID of the message that will be scrolled to
80 | */
81 | async openChatWindowAt(msgId) {
82 | await this.pupPage.evaluate(async msgId => {
83 | let msg = await window.Store.Msg.get(msgId);
84 | await window.Store.Cmd.openChatAt(msg.chat, msg.chat.getSearchContext(msg));
85 | }, msgId);
86 | }
87 |
88 | /**
89 | * Opens the Message Drawer
90 | * @param {string} msgId ID of the message drawer that will be opened
91 | */
92 | async openMessageDrawer(msgId) {
93 | await this.pupPage.evaluate(async msgId => {
94 | let msg = await window.Store.Msg.get(msgId);
95 | await window.Store.Cmd.msgInfoDrawer(msg);
96 | }, msgId);
97 | }
98 |
99 | /**
100 | * Closes the Right Drawer
101 | */
102 | async closeRightDrawer() {
103 | await this.pupPage.evaluate(async () => {
104 | await window.Store.Cmd.closeDrawerRight();
105 | });
106 | }
107 |
108 | /**
109 | * Get all Features
110 | */
111 | async getFeatures() {
112 | return await this.pupPage.evaluate(() => {
113 | return window.Store.Features.F;
114 | });
115 | }
116 |
117 | /**
118 | * Check if Feature is enabled
119 | * @param {string} feature status to check
120 | */
121 | async checkFeatureStatus(feature) {
122 | return await this.pupPage.evaluate((feature) => {
123 | return window.Store.Features.supportsFeature(feature);
124 | }, feature);
125 | }
126 |
127 | /**
128 | * Enable Features
129 | * @param {string[]} features to be enabled
130 | */
131 | async enableFeatures(features) {
132 | await this.pupPage.evaluate((features) => {
133 | for (const feature in features) {
134 | window.Store.Features.setFeature(features[feature], true);
135 | }
136 | }, features);
137 | }
138 |
139 | /**
140 | * Disable Features
141 | * @param {string[]} features to be disabled
142 | */
143 | async disableFeatures(features) {
144 | await this.pupPage.evaluate((features) => {
145 | for (const feature in features) {
146 | window.Store.Features.setFeature(features[feature], false);
147 | }
148 | }, features);
149 | }
150 | }
151 |
152 | module.exports = InterfaceController;
153 |
154 | Source: structures/
Represents a Product on WhatsAppBusiness
32 |Currency
89 |Product metadata
93 |Product ID
98 |Product Name
103 |Price
108 |Product Quantity
113 |Product Thumbnail
118 |'use strict';
33 |
34 | const fs = require('fs');
35 | const path = require('path');
36 | const mime = require('mime');
37 | const fetch = require('node-fetch');
38 | const { URL } = require('url');
39 |
40 | /**
41 | * Media attached to a message
42 | * @param {string} mimetype MIME type of the attachment
43 | * @param {string} data Base64-encoded data of the file
44 | * @param {?string} filename Document file name
45 | */
46 | class MessageMedia {
47 | constructor(mimetype, data, filename) {
48 | /**
49 | * MIME type of the attachment
50 | * @type {string}
51 | */
52 | this.mimetype = mimetype;
53 |
54 | /**
55 | * Base64 encoded data that represents the file
56 | * @type {string}
57 | */
58 | this.data = data;
59 |
60 | /**
61 | * Name of the file (for documents)
62 | * @type {?string}
63 | */
64 | this.filename = filename;
65 | }
66 |
67 | /**
68 | * Creates a MessageMedia instance from a local file path
69 | * @param {string} filePath
70 | * @returns {MessageMedia}
71 | */
72 | static fromFilePath(filePath) {
73 | const b64data = fs.readFileSync(filePath, {encoding: 'base64'});
74 | const mimetype = mime.getType(filePath);
75 | const filename = path.basename(filePath);
76 |
77 | return new MessageMedia(mimetype, b64data, filename);
78 | }
79 |
80 | /**
81 | * Creates a MessageMedia instance from a URL
82 | * @param {string} url
83 | * @param {Object} [options]
84 | * @param {boolean} [options.unsafeMime=false]
85 | * @param {string} [options.filename]
86 | * @param {object} [options.client]
87 | * @param {object} [options.reqOptions]
88 | * @param {number} [options.reqOptions.size=0]
89 | * @returns {Promise<MessageMedia>}
90 | */
91 | static async fromUrl(url, options = {}) {
92 | const pUrl = new URL(url);
93 | let mimetype = mime.getType(pUrl.pathname);
94 |
95 | if (!mimetype && !options.unsafeMime)
96 | throw new Error('Unable to determine MIME type using URL. Set unsafeMime to true to download it anyway.');
97 |
98 | async function fetchData (url, options) {
99 | const reqOptions = Object.assign({ headers: { accept: 'image/* video/* text/* audio/*' } }, options);
100 | const response = await fetch(url, reqOptions);
101 | const mime = response.headers.get('Content-Type');
102 |
103 | const contentDisposition = response.headers.get('Content-Disposition');
104 | const name = contentDisposition ? contentDisposition.match(/((?<=filename=")(.*)(?="))/) : null;
105 |
106 | let data = '';
107 | if (response.buffer) {
108 | data = (await response.buffer()).toString('base64');
109 | } else {
110 | const bArray = new Uint8Array(await response.arrayBuffer());
111 | bArray.forEach((b) => {
112 | data += String.fromCharCode(b);
113 | });
114 | data = btoa(data);
115 | }
116 |
117 | return { data, mime, name };
118 | }
119 |
120 | const res = options.client
121 | ? (await options.client.pupPage.evaluate(fetchData, url, options.reqOptions))
122 | : (await fetchData(url, options.reqOptions));
123 |
124 | const filename = options.filename ||
125 | (res.name ? res.name[0] : (pUrl.pathname.split('/').pop() || 'file'));
126 |
127 | if (!mimetype)
128 | mimetype = res.mime;
129 |
130 | return new MessageMedia(mimetype, res.data, filename);
131 | }
132 | }
133 |
134 | module.exports = MessageMedia;
135 |
136 | Source: structures/
Location information
32 || Name | 72 |Type | 73 |Optional | 74 |Description | 75 |
|---|---|---|---|
|
80 | latitude 81 | |
82 |
83 | 84 | |
85 |
86 | 87 | |
88 | 89 | | 90 |
|
93 | longitude 94 | |
95 |
96 | 97 | |
98 |
99 | 100 | |
101 | 102 | | 103 |
|
106 | description 107 | |
108 |
109 | 110 | |
111 |
112 | 113 | |
114 |
115 | Value can be null. 116 | |
117 |
Name for the location
130 |Location latitude
135 |Location longitude
140 |'use strict';
33 |
34 | exports.WhatsWebURL = 'https://web.whatsapp.com/';
35 |
36 | exports.DefaultOptions = {
37 | puppeteer: {
38 | headless: true,
39 | defaultViewport: null
40 | },
41 | authTimeoutMs: 0,
42 | qrMaxRetries: 0,
43 | takeoverOnConflict: false,
44 | takeoverTimeoutMs: 0,
45 | userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
46 | ffmpegPath: 'ffmpeg',
47 | bypassCSP: false
48 | };
49 |
50 | /**
51 | * Client status
52 | * @readonly
53 | * @enum {number}
54 | */
55 | exports.Status = {
56 | INITIALIZING: 0,
57 | AUTHENTICATING: 1,
58 | READY: 3
59 | };
60 |
61 | /**
62 | * Events that can be emitted by the client
63 | * @readonly
64 | * @enum {string}
65 | */
66 | exports.Events = {
67 | AUTHENTICATED: 'authenticated',
68 | AUTHENTICATION_FAILURE: 'auth_failure',
69 | READY: 'ready',
70 | MESSAGE_RECEIVED: 'message',
71 | MESSAGE_CREATE: 'message_create',
72 | MESSAGE_REVOKED_EVERYONE: 'message_revoke_everyone',
73 | MESSAGE_REVOKED_ME: 'message_revoke_me',
74 | MESSAGE_ACK: 'message_ack',
75 | MEDIA_UPLOADED: 'media_uploaded',
76 | GROUP_JOIN: 'group_join',
77 | GROUP_LEAVE: 'group_leave',
78 | GROUP_UPDATE: 'group_update',
79 | QR_RECEIVED: 'qr',
80 | DISCONNECTED: 'disconnected',
81 | STATE_CHANGED: 'change_state',
82 | BATTERY_CHANGED: 'change_battery',
83 | INCOMING_CALL: 'incoming_call'
84 | };
85 |
86 | /**
87 | * Message types
88 | * @readonly
89 | * @enum {string}
90 | */
91 | exports.MessageTypes = {
92 | TEXT: 'chat',
93 | AUDIO: 'audio',
94 | VOICE: 'ptt',
95 | IMAGE: 'image',
96 | VIDEO: 'video',
97 | DOCUMENT: 'document',
98 | STICKER: 'sticker',
99 | LOCATION: 'location',
100 | CONTACT_CARD: 'vcard',
101 | CONTACT_CARD_MULTI: 'multi_vcard',
102 | ORDER: 'order',
103 | REVOKED: 'revoked',
104 | PRODUCT: 'product',
105 | UNKNOWN: 'unknown',
106 | GROUP_INVITE: 'groups_v4_invite',
107 | LIST: 'list',
108 | LIST_RESPONSE: 'list_response',
109 | BUTTONS_RESPONSE: 'buttons_response',
110 | PAYMENT: 'payment',
111 | BROADCAST_NOTIFICATION: 'broadcast_notification',
112 | CALL_LOG: 'call_log',
113 | CIPHERTEXT: 'ciphertext',
114 | DEBUG: 'debug',
115 | E2E_NOTIFICATION: 'e2e_notification',
116 | GP2: 'gp2',
117 | GROUP_NOTIFICATION: 'group_notification',
118 | HSM: 'hsm',
119 | INTERACTIVE: 'interactive',
120 | NATIVE_FLOW: 'native_flow',
121 | NOTIFICATION: 'notification',
122 | NOTIFICATION_TEMPLATE: 'notification_template',
123 | OVERSIZED: 'oversized',
124 | PROTOCOL: 'protocol',
125 | REACTION: 'reaction',
126 | TEMPLATE_BUTTON_REPLY: 'template_button_reply',
127 | };
128 |
129 | /**
130 | * Group notification types
131 | * @readonly
132 | * @enum {string}
133 | */
134 | exports.GroupNotificationTypes = {
135 | ADD: 'add',
136 | INVITE: 'invite',
137 | REMOVE: 'remove',
138 | LEAVE: 'leave',
139 | SUBJECT: 'subject',
140 | DESCRIPTION: 'description',
141 | PICTURE: 'picture',
142 | ANNOUNCE: 'announce',
143 | RESTRICT: 'restrict',
144 | };
145 |
146 | /**
147 | * Chat types
148 | * @readonly
149 | * @enum {string}
150 | */
151 | exports.ChatTypes = {
152 | SOLO: 'solo',
153 | GROUP: 'group',
154 | UNKNOWN: 'unknown'
155 | };
156 |
157 | /**
158 | * WhatsApp state
159 | * @readonly
160 | * @enum {string}
161 | */
162 | exports.WAState = {
163 | CONFLICT: 'CONFLICT',
164 | CONNECTED: 'CONNECTED',
165 | DEPRECATED_VERSION: 'DEPRECATED_VERSION',
166 | OPENING: 'OPENING',
167 | PAIRING: 'PAIRING',
168 | PROXYBLOCK: 'PROXYBLOCK',
169 | SMB_TOS_BLOCK: 'SMB_TOS_BLOCK',
170 | TIMEOUT: 'TIMEOUT',
171 | TOS_BLOCK: 'TOS_BLOCK',
172 | UNLAUNCHED: 'UNLAUNCHED',
173 | UNPAIRED: 'UNPAIRED',
174 | UNPAIRED_IDLE: 'UNPAIRED_IDLE'
175 | };
176 |
177 | /**
178 | * Message ACK
179 | * @readonly
180 | * @enum {number}
181 | */
182 | exports.MessageAck = {
183 | ACK_ERROR: -1,
184 | ACK_PENDING: 0,
185 | ACK_SERVER: 1,
186 | ACK_DEVICE: 2,
187 | ACK_READ: 3,
188 | ACK_PLAYED: 4,
189 | };
190 |
191 |