Auth Strategies (#1257)

* auth strategies

* default to no auth

* rename base auth strategy

* rename base strategy cont.

* refactor auth strategy methods and LocalAuth

* activate old session options even if is falsy value

* move restartOnAuthFail to LegacyAuthStrategy option

* add link to guide item

* update example/shell

* types
This commit is contained in:
Pedro S. Lopez
2022-02-27 22:02:49 -04:00
committed by GitHub
parent 0d55d40885
commit f6de161c7d
12 changed files with 266 additions and 116 deletions

View File

@@ -0,0 +1,24 @@
'use strict';
/**
* Base class which all authentication strategies extend
*/
class BaseAuthStrategy {
constructor() {}
setup(client) {
this.client = client;
}
async beforeBrowserInitialized() {}
async afterBrowserInitialized() {}
async onAuthenticationNeeded() {
return {
failed: false,
restart: false,
failureEventPayload: undefined
};
}
async getAuthEventPayload() {}
async logout() {}
}
module.exports = BaseAuthStrategy;

View File

@@ -0,0 +1,72 @@
'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.Features.features.MD_BACKEND;
});
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;

View File

@@ -0,0 +1,54 @@
'use strict';
const path = require('path');
const fs = require('fs');
const BaseAuthStrategy = require('./BaseAuthStrategy');
/**
* Local directory-based authentication
* @param {object} options - options
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
*/
class LocalAuth extends BaseAuthStrategy {
constructor({ clientId, dataPath }={}) {
super();
const idRegex = /^[-_\w]+$/i;
if(clientId && !idRegex.test(clientId)) {
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
}
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
this.clientId = clientId;
}
async beforeBrowserInitialized() {
const puppeteerOpts = this.client.options.puppeteer;
if(puppeteerOpts.userDataDir) {
throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
}
const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
const dirPath = path.join(this.dataPath, sessionDirName);
fs.mkdirSync(dirPath, { recursive: true });
this.client.options.puppeteer = {
...puppeteerOpts,
userDataDir: dirPath
};
this.userDataDir = dirPath;
}
async logout() {
if (this.userDataDir) {
return (fs.rmSync ? fs.rmSync : fs.rmdirSync).call(this.userDataDir, { recursive: true });
}
}
}
module.exports = LocalAuth;

View File

@@ -0,0 +1,12 @@
'use strict';
const BaseAuthStrategy = require('./BaseAuthStrategy');
/**
* No session restoring functionality
* Will need to authenticate via QR code every time
*/
class NoAuth extends BaseAuthStrategy { }
module.exports = NoAuth;