mirror of
https://github.com/cheveguerra/whatsapp-web.js.git
synced 2026-04-18 03:29:14 +00:00
Compare commits
1 Commits
WaWJS2
...
pedroslope
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d846611cc4 |
19
index.d.ts
vendored
19
index.d.ts
vendored
@@ -322,14 +322,6 @@ declare namespace WAWebJS {
|
|||||||
/** How many times should the qrcode be refreshed before giving up
|
/** How many times should the qrcode be refreshed before giving up
|
||||||
* @default 0 (disabled) */
|
* @default 0 (disabled) */
|
||||||
qrMaxRetries?: number,
|
qrMaxRetries?: number,
|
||||||
/**
|
|
||||||
* @deprecated This option should be set directly on the LegacySessionAuth
|
|
||||||
*/
|
|
||||||
restartOnAuthFail?: boolean
|
|
||||||
/**
|
|
||||||
* @deprecated Only here for backwards-compatibility. You should move to using LocalAuth, or set the authStrategy to LegacySessionAuth explicitly.
|
|
||||||
*/
|
|
||||||
session?: ClientSession
|
|
||||||
/** If another whatsapp web session is detected (another browser), take over the session in the current browser
|
/** If another whatsapp web session is detected (another browser), take over the session in the current browser
|
||||||
* @default false */
|
* @default false */
|
||||||
takeoverOnConflict?: boolean,
|
takeoverOnConflict?: boolean,
|
||||||
@@ -405,17 +397,6 @@ declare namespace WAWebJS {
|
|||||||
extract: (options: { session: string, path: string }) => Promise<any> | any,
|
extract: (options: { session: string, path: string }) => Promise<any> | any,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Legacy session auth strategy
|
|
||||||
* Not compatible with multi-device accounts.
|
|
||||||
*/
|
|
||||||
export class LegacySessionAuth extends AuthStrategy {
|
|
||||||
constructor(options?: {
|
|
||||||
session?: ClientSession,
|
|
||||||
restartOnAuthFail?: boolean,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a WhatsApp client session
|
* Represents a WhatsApp client session
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ const { ExposeStore, LoadUtils } = require('./util/Injected');
|
|||||||
const ChatFactory = require('./factories/ChatFactory');
|
const ChatFactory = require('./factories/ChatFactory');
|
||||||
const ContactFactory = require('./factories/ContactFactory');
|
const ContactFactory = require('./factories/ContactFactory');
|
||||||
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification, Label, Call, Buttons, List, Reaction } = require('./structures');
|
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification, Label, Call, Buttons, List, Reaction } = require('./structures');
|
||||||
const LegacySessionAuth = require('./authStrategies/LegacySessionAuth');
|
|
||||||
const NoAuth = require('./authStrategies/NoAuth');
|
const NoAuth = require('./authStrategies/NoAuth');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,8 +21,6 @@ const NoAuth = require('./authStrategies/NoAuth');
|
|||||||
* @param {number} options.authTimeoutMs - Timeout for authentication selector in puppeteer
|
* @param {number} options.authTimeoutMs - Timeout for authentication selector in puppeteer
|
||||||
* @param {object} options.puppeteer - Puppeteer launch options. View docs here: https://github.com/puppeteer/puppeteer/
|
* @param {object} options.puppeteer - Puppeteer launch options. View docs here: https://github.com/puppeteer/puppeteer/
|
||||||
* @param {number} options.qrMaxRetries - How many times should the qrcode be refreshed before giving up
|
* @param {number} options.qrMaxRetries - How many times should the qrcode be refreshed before giving up
|
||||||
* @param {string} options.restartOnAuthFail - @deprecated This option should be set directly on the LegacySessionAuth.
|
|
||||||
* @param {object} options.session - @deprecated Only here for backwards-compatibility. You should move to using LocalAuth, or set the authStrategy to LegacySessionAuth explicitly.
|
|
||||||
* @param {number} options.takeoverOnConflict - If another whatsapp web session is detected (another browser), take over the session in the current browser
|
* @param {number} options.takeoverOnConflict - If another whatsapp web session is detected (another browser), take over the session in the current browser
|
||||||
* @param {number} options.takeoverTimeoutMs - How much time to wait before taking over the session
|
* @param {number} options.takeoverTimeoutMs - How much time to wait before taking over the session
|
||||||
* @param {string} options.userAgent - User agent to use in puppeteer
|
* @param {string} options.userAgent - User agent to use in puppeteer
|
||||||
@@ -52,23 +49,10 @@ class Client extends EventEmitter {
|
|||||||
|
|
||||||
this.options = Util.mergeDefault(DefaultOptions, options);
|
this.options = Util.mergeDefault(DefaultOptions, options);
|
||||||
|
|
||||||
if(!this.options.authStrategy) {
|
if(this.options.authStrategy) {
|
||||||
if(Object.prototype.hasOwnProperty.call(this.options, 'session')) {
|
|
||||||
process.emitWarning(
|
|
||||||
'options.session is deprecated and will be removed in a future release due to incompatibility with multi-device. ' +
|
|
||||||
'Use the LocalAuth authStrategy, don\'t pass in a session as an option, or suppress this warning by using the LegacySessionAuth strategy explicitly (see https://wwebjs.dev/guide/authentication.html#legacysessionauth-strategy).',
|
|
||||||
'DeprecationWarning'
|
|
||||||
);
|
|
||||||
|
|
||||||
this.authStrategy = new LegacySessionAuth({
|
|
||||||
session: this.options.session,
|
|
||||||
restartOnAuthFail: this.options.restartOnAuthFail
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.authStrategy = new NoAuth();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.authStrategy = this.options.authStrategy;
|
this.authStrategy = this.options.authStrategy;
|
||||||
|
} else {
|
||||||
|
this.authStrategy = new NoAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authStrategy.setup(this);
|
this.authStrategy.setup(this);
|
||||||
@@ -822,16 +806,11 @@ class Client extends EventEmitter {
|
|||||||
* @returns {Promise<Boolean>}
|
* @returns {Promise<Boolean>}
|
||||||
*/
|
*/
|
||||||
async setDisplayName(displayName) {
|
async setDisplayName(displayName) {
|
||||||
const couldSet = await this.pupPage.evaluate(async displayName => {
|
const couldSet = await this.pupPage.evaluate(async () => {
|
||||||
if(!window.Store.Conn.canSetMyPushname()) return false;
|
if(!window.Store.Conn.canSetMyPushname()) return false;
|
||||||
|
|
||||||
if(window.Store.MDBackend) {
|
// TODO for MD
|
||||||
// TODO
|
return false;
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
const res = await window.Store.Wap.setPushname(displayName);
|
|
||||||
return !res.status || res.status === 200;
|
|
||||||
}
|
|
||||||
}, displayName);
|
}, displayName);
|
||||||
|
|
||||||
return couldSet;
|
return couldSet;
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Legacy session auth strategy
|
|
||||||
* Not compatible with multi-device accounts.
|
|
||||||
* @param {object} options - options
|
|
||||||
* @param {string} options.restartOnAuthFail - Restart client with a new session (i.e. use null 'session' var) if authentication fails
|
|
||||||
* @param {object} options.session - Whatsapp session to restore. If not set, will start a new session
|
|
||||||
* @param {string} options.session.WABrowserId
|
|
||||||
* @param {string} options.session.WASecretBundle
|
|
||||||
* @param {string} options.session.WAToken1
|
|
||||||
* @param {string} options.session.WAToken2
|
|
||||||
*/
|
|
||||||
class LegacySessionAuth extends BaseAuthStrategy {
|
|
||||||
constructor({ session, restartOnAuthFail }={}) {
|
|
||||||
super();
|
|
||||||
this.session = session;
|
|
||||||
this.restartOnAuthFail = restartOnAuthFail;
|
|
||||||
}
|
|
||||||
|
|
||||||
async afterBrowserInitialized() {
|
|
||||||
if(this.session) {
|
|
||||||
await this.client.pupPage.evaluateOnNewDocument(session => {
|
|
||||||
if (document.referrer === 'https://whatsapp.com/') {
|
|
||||||
localStorage.clear();
|
|
||||||
localStorage.setItem('WABrowserId', session.WABrowserId);
|
|
||||||
localStorage.setItem('WASecretBundle', session.WASecretBundle);
|
|
||||||
localStorage.setItem('WAToken1', session.WAToken1);
|
|
||||||
localStorage.setItem('WAToken2', session.WAToken2);
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem('remember-me', 'true');
|
|
||||||
}, this.session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async onAuthenticationNeeded() {
|
|
||||||
if(this.session) {
|
|
||||||
this.session = null;
|
|
||||||
return {
|
|
||||||
failed: true,
|
|
||||||
restart: this.restartOnAuthFail,
|
|
||||||
failureEventPayload: 'Unable to log in. Are the session details valid?'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return { failed: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAuthEventPayload() {
|
|
||||||
const isMD = await this.client.pupPage.evaluate(() => {
|
|
||||||
return window.Store.MDBackend;
|
|
||||||
});
|
|
||||||
|
|
||||||
if(isMD) throw new Error('Authenticating via JSON session is not supported for MultiDevice-enabled WhatsApp accounts.');
|
|
||||||
|
|
||||||
const localStorage = JSON.parse(await this.client.pupPage.evaluate(() => {
|
|
||||||
return JSON.stringify(window.localStorage);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return {
|
|
||||||
WABrowserId: localStorage.WABrowserId,
|
|
||||||
WASecretBundle: localStorage.WASecretBundle,
|
|
||||||
WAToken1: localStorage.WAToken1,
|
|
||||||
WAToken2: localStorage.WAToken2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = LegacySessionAuth;
|
|
||||||
@@ -13,7 +13,6 @@ exports.ExposeStore = (moduleRaidStr) => {
|
|||||||
window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd;
|
window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd;
|
||||||
window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
|
window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
|
||||||
window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager;
|
window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager;
|
||||||
window.Store.MDBackend = window.mR.findModule('isMDBackend')[0].isMDBackend();
|
|
||||||
window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].LegacyPhoneFeatures;
|
window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].LegacyPhoneFeatures;
|
||||||
window.Store.GroupMetadata = window.mR.findModule((module) => module.default && module.default.handlePendingInvite)[0].default;
|
window.Store.GroupMetadata = window.mR.findModule((module) => module.default && module.default.handlePendingInvite)[0].default;
|
||||||
window.Store.Invite = window.mR.findModule('sendJoinGroupViaInvite')[0];
|
window.Store.Invite = window.mR.findModule('sendJoinGroupViaInvite')[0];
|
||||||
@@ -162,16 +161,7 @@ exports.LoadUtils = () => {
|
|||||||
if (options.linkPreview) {
|
if (options.linkPreview) {
|
||||||
delete options.linkPreview;
|
delete options.linkPreview;
|
||||||
|
|
||||||
// Not supported yet by WhatsApp Web on MD
|
// TODO Not supported yet by WhatsApp Web on MD
|
||||||
if(!window.Store.MDBackend) {
|
|
||||||
const link = window.Store.Validators.findLink(content);
|
|
||||||
if (link) {
|
|
||||||
const preview = await window.Store.Wap.queryLinkPreview(link.url);
|
|
||||||
preview.preview = true;
|
|
||||||
preview.subtype = 'url';
|
|
||||||
options = { ...options, ...preview };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let buttonOptions = {};
|
let buttonOptions = {};
|
||||||
@@ -215,13 +205,12 @@ exports.LoadUtils = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const meUser = window.Store.User.getMaybeMeUser();
|
const meUser = window.Store.User.getMaybeMeUser();
|
||||||
const isMD = window.Store.MDBackend;
|
|
||||||
|
|
||||||
const newMsgId = new window.Store.MsgKey({
|
const newMsgId = new window.Store.MsgKey({
|
||||||
from: meUser,
|
from: meUser,
|
||||||
to: chat.id,
|
to: chat.id,
|
||||||
id: window.Store.MsgKey.newId(),
|
id: window.Store.MsgKey.newId(),
|
||||||
participant: isMD && chat.id.isGroup() ? meUser : undefined,
|
participant: chat.id.isGroup() ? meUser : undefined,
|
||||||
selfDir: 'out',
|
selfDir: 'out',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -526,9 +515,8 @@ exports.LoadUtils = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
window.WWebJS.sendChatstate = async (state, chatId) => {
|
window.WWebJS.sendChatstate = async (state, chatId) => {
|
||||||
if (window.Store.MDBackend) {
|
chatId = window.Store.WidFactory.createWid(chatId);
|
||||||
chatId = window.Store.WidFactory.createWid(chatId);
|
|
||||||
}
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'typing':
|
case 'typing':
|
||||||
await window.Store.ChatState.sendChatStateComposing(chatId);
|
await window.Store.ChatState.sendChatStateComposing(chatId);
|
||||||
|
|||||||
121
tests/client.js
121
tests/client.js
@@ -8,14 +8,12 @@ const Contact = require('../src/structures/Contact');
|
|||||||
const Message = require('../src/structures/Message');
|
const Message = require('../src/structures/Message');
|
||||||
const MessageMedia = require('../src/structures/MessageMedia');
|
const MessageMedia = require('../src/structures/MessageMedia');
|
||||||
const Location = require('../src/structures/Location');
|
const Location = require('../src/structures/Location');
|
||||||
const LegacySessionAuth = require('../src/authStrategies/LegacySessionAuth');
|
const { MessageTypes, DefaultOptions } = require('../src/util/Constants');
|
||||||
const { MessageTypes, WAState, DefaultOptions } = require('../src/util/Constants');
|
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
chai.use(chaiAsPromised);
|
chai.use(chaiAsPromised);
|
||||||
|
|
||||||
const remoteId = helper.remoteId;
|
const remoteId = helper.remoteId;
|
||||||
const isMD = helper.isMD();
|
|
||||||
|
|
||||||
describe('Client', function() {
|
describe('Client', function() {
|
||||||
describe('User Agent', function () {
|
describe('User Agent', function () {
|
||||||
@@ -155,123 +153,6 @@ describe('Client', function() {
|
|||||||
|
|
||||||
await client.destroy();
|
await client.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('LegacySessionAuth', function () {
|
|
||||||
it('should fail auth if session is invalid', async function() {
|
|
||||||
this.timeout(40000);
|
|
||||||
|
|
||||||
const authFailCallback = sinon.spy();
|
|
||||||
const qrCallback = sinon.spy();
|
|
||||||
const readyCallback = sinon.spy();
|
|
||||||
|
|
||||||
const client = helper.createClient({
|
|
||||||
options: {
|
|
||||||
authStrategy: new LegacySessionAuth({
|
|
||||||
session: {
|
|
||||||
WABrowserId: 'invalid',
|
|
||||||
WASecretBundle: 'invalid',
|
|
||||||
WAToken1: 'invalid',
|
|
||||||
WAToken2: 'invalid'
|
|
||||||
},
|
|
||||||
restartOnAuthFail: false,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('qr', qrCallback);
|
|
||||||
client.on('auth_failure', authFailCallback);
|
|
||||||
client.on('ready', readyCallback);
|
|
||||||
|
|
||||||
client.initialize();
|
|
||||||
|
|
||||||
await helper.sleep(25000);
|
|
||||||
|
|
||||||
expect(authFailCallback.called).to.equal(true);
|
|
||||||
expect(authFailCallback.args[0][0]).to.equal('Unable to log in. Are the session details valid?');
|
|
||||||
|
|
||||||
expect(readyCallback.called).to.equal(false);
|
|
||||||
expect(qrCallback.called).to.equal(false);
|
|
||||||
|
|
||||||
await client.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can restart without a session if session was invalid and restartOnAuthFail=true', async function() {
|
|
||||||
this.timeout(40000);
|
|
||||||
|
|
||||||
const authFailCallback = sinon.spy();
|
|
||||||
const qrCallback = sinon.spy();
|
|
||||||
|
|
||||||
const client = helper.createClient({
|
|
||||||
options: {
|
|
||||||
authStrategy: new LegacySessionAuth({
|
|
||||||
session: {
|
|
||||||
WABrowserId: 'invalid',
|
|
||||||
WASecretBundle: 'invalid',
|
|
||||||
WAToken1: 'invalid',
|
|
||||||
WAToken2: 'invalid'
|
|
||||||
},
|
|
||||||
restartOnAuthFail: true,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('auth_failure', authFailCallback);
|
|
||||||
client.on('qr', qrCallback);
|
|
||||||
|
|
||||||
client.initialize();
|
|
||||||
|
|
||||||
await helper.sleep(35000);
|
|
||||||
|
|
||||||
expect(authFailCallback.called).to.equal(true);
|
|
||||||
expect(qrCallback.called).to.equal(true);
|
|
||||||
expect(qrCallback.args[0][0]).to.have.lengthOf(152);
|
|
||||||
|
|
||||||
await client.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Non-MD only', function () {
|
|
||||||
if(!isMD) {
|
|
||||||
it('can take over if client was logged in somewhere else with takeoverOnConflict=true', async function() {
|
|
||||||
this.timeout(40000);
|
|
||||||
|
|
||||||
const readyCallback1 = sinon.spy();
|
|
||||||
const readyCallback2 = sinon.spy();
|
|
||||||
const disconnectedCallback1 = sinon.spy();
|
|
||||||
const disconnectedCallback2 = sinon.spy();
|
|
||||||
|
|
||||||
const client1 = helper.createClient({
|
|
||||||
authenticated: true,
|
|
||||||
options: { takeoverOnConflict: true, takeoverTimeoutMs: 5000 }
|
|
||||||
});
|
|
||||||
const client2 = helper.createClient({authenticated: true});
|
|
||||||
|
|
||||||
client1.on('ready', readyCallback1);
|
|
||||||
client2.on('ready', readyCallback2);
|
|
||||||
client1.on('disconnected', disconnectedCallback1);
|
|
||||||
client2.on('disconnected', disconnectedCallback2);
|
|
||||||
|
|
||||||
await client1.initialize();
|
|
||||||
expect(readyCallback1.called).to.equal(true);
|
|
||||||
expect(readyCallback2.called).to.equal(false);
|
|
||||||
expect(disconnectedCallback1.called).to.equal(false);
|
|
||||||
expect(disconnectedCallback2.called).to.equal(false);
|
|
||||||
|
|
||||||
await client2.initialize();
|
|
||||||
expect(readyCallback2.called).to.equal(true);
|
|
||||||
expect(disconnectedCallback1.called).to.equal(false);
|
|
||||||
expect(disconnectedCallback2.called).to.equal(false);
|
|
||||||
|
|
||||||
// wait for takeoverTimeoutMs to kick in
|
|
||||||
await helper.sleep(5200);
|
|
||||||
expect(disconnectedCallback1.called).to.equal(false);
|
|
||||||
expect(disconnectedCallback2.called).to.equal(true);
|
|
||||||
expect(disconnectedCallback2.calledWith(WAState.CONFLICT)).to.equal(true);
|
|
||||||
|
|
||||||
await client1.destroy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Authenticated', function() {
|
describe('Authenticated', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user