Path: blob/master/node_modules/@adiwajshing/baileys/lib/LegacySocket/auth.js
1129 views
"use strict";1var __importDefault = (this && this.__importDefault) || function (mod) {2return (mod && mod.__esModule) ? mod : { "default": mod };3};4Object.defineProperty(exports, "__esModule", { value: true });5const boom_1 = require("@hapi/boom");6const events_1 = __importDefault(require("events"));7const Types_1 = require("../Types");8const Utils_1 = require("../Utils");9const socket_1 = require("./socket");10const makeAuthSocket = (config) => {11const { logger, version, browser, connectTimeoutMs, printQRInTerminal, auth: initialAuthInfo } = config;12const ev = new events_1.default();13const authInfo = initialAuthInfo || (0, Utils_1.newLegacyAuthCreds)();14const state = {15legacy: {16phoneConnected: false,17},18connection: 'connecting',19};20const socket = (0, socket_1.makeSocket)(config);21const { ws } = socket;22let curveKeys;23let initTimeout;24ws.on('phone-connection', ({ value: phoneConnected }) => {25updateState({ legacy: { ...state.legacy, phoneConnected } });26});27// add close listener28ws.on('ws-close', (error) => {29logger.info({ error }, 'closed connection to WhatsApp');30initTimeout && clearTimeout(initTimeout);31// if no reconnects occur32// send close event33updateState({34connection: 'close',35qr: undefined,36lastDisconnect: {37error,38date: new Date()39}40});41});42/** Can you login to WA without scanning the QR */43const canLogin = () => !!(authInfo === null || authInfo === void 0 ? void 0 : authInfo.encKey) && !!(authInfo === null || authInfo === void 0 ? void 0 : authInfo.macKey);44const updateState = (update) => {45Object.assign(state, update);46ev.emit('connection.update', update);47};48/**49* Logs you out from WA50* If connected, invalidates the credentials with the server51*/52const logout = async () => {53if (state.connection === 'open') {54await socket.sendNode({55json: ['admin', 'Conn', 'disconnect'],56tag: 'goodbye'57});58}59// will call state update to close connection60socket === null || socket === void 0 ? void 0 : socket.end(new boom_1.Boom('Logged Out', { statusCode: Types_1.DisconnectReason.loggedOut }));61};62const updateEncKeys = () => {63// update the keys so we can decrypt traffic64socket.updateKeys({ encKey: authInfo.encKey, macKey: authInfo.macKey });65};66const generateKeysForAuth = async (ref, ttl) => {67curveKeys = Utils_1.Curve.generateKeyPair();68const publicKey = Buffer.from(curveKeys.public).toString('base64');69const qrLoop = ttl => {70const qr = [ref, publicKey, authInfo.clientID].join(',');71updateState({ qr });72initTimeout = setTimeout(async () => {73var _a;74if (state.connection !== 'connecting') {75return;76}77logger.debug('regenerating QR');78try {79// request new QR80const { ref: newRef, ttl: newTTL } = await socket.query({81json: ['admin', 'Conn', 'reref'],82expect200: true,83longTag: true,84requiresPhoneConnection: false85});86ttl = newTTL;87ref = newRef;88}89catch (error) {90logger.error({ error }, 'error in QR gen');91if (((_a = error.output) === null || _a === void 0 ? void 0 : _a.statusCode) === 429) { // too many QR requests92socket.end(error);93return;94}95}96qrLoop(ttl);97}, ttl || 20000); // default is 20s, on the off-chance ttl is not present98};99qrLoop(ttl);100};101const onOpen = async () => {102var _a, _b;103const canDoLogin = canLogin();104const initQuery = (async () => {105const { ref, ttl } = await socket.query({106json: ['admin', 'init', version, browser, authInfo.clientID, true],107expect200: true,108longTag: true,109requiresPhoneConnection: false110});111if (!canDoLogin) {112generateKeysForAuth(ref, ttl);113}114})();115let loginTag;116if (canDoLogin) {117updateEncKeys();118// if we have the info to restore a closed session119const json = [120'admin',121'login',122authInfo.clientToken,123authInfo.serverToken,124authInfo.clientID,125'takeover'126];127loginTag = socket.generateMessageTag(true);128// send login every 10s129const sendLoginReq = () => {130if (state.connection === 'open') {131logger.warn('Received login timeout req when state=open, ignoring...');132return;133}134logger.info('sending login request');135socket.sendNode({136json,137tag: loginTag138});139initTimeout = setTimeout(sendLoginReq, 10000);140};141sendLoginReq();142}143await initQuery;144// wait for response with tag "s1"145let response = await Promise.race([146socket.waitForMessage('s1', false, undefined).promise,147...(loginTag ? [socket.waitForMessage(loginTag, false, connectTimeoutMs).promise] : [])148]);149initTimeout && clearTimeout(initTimeout);150initTimeout = undefined;151if (response.status && response.status !== 200) {152throw new boom_1.Boom('Unexpected error in login', { data: response, statusCode: response.status });153}154// if its a challenge request (we get it when logging in)155if ((_a = response[1]) === null || _a === void 0 ? void 0 : _a.challenge) {156const json = (0, Utils_1.computeChallengeResponse)(response[1].challenge, authInfo);157logger.info('resolving login challenge');158await socket.query({ json, expect200: true, timeoutMs: connectTimeoutMs });159response = await socket.waitForMessage('s2', true).promise;160}161if (!response || !response[1]) {162throw new boom_1.Boom('Received unexpected login response', { data: response });163}164if (response[1].type === 'upgrade_md_prod') {165throw new boom_1.Boom('Require multi-device edition', { statusCode: Types_1.DisconnectReason.multideviceMismatch });166}167// validate the new connection168const { user, auth } = (0, Utils_1.validateNewConnection)(response[1], authInfo, curveKeys); // validate the connection169const isNewLogin = user.id !== ((_b = state.legacy.user) === null || _b === void 0 ? void 0 : _b.id);170Object.assign(authInfo, auth);171updateEncKeys();172logger.info({ user }, 'logged in');173ev.emit('creds.update', auth);174updateState({175connection: 'open',176legacy: {177phoneConnected: true,178user,179},180isNewLogin,181qr: undefined182});183};184ws.once('open', async () => {185try {186await onOpen();187}188catch (error) {189socket.end(error);190}191});192if (printQRInTerminal) {193(0, Utils_1.printQRIfNecessaryListener)(ev, logger);194}195process.nextTick(() => {196ev.emit('connection.update', {197...state198});199});200return {201...socket,202state,203authInfo,204ev,205canLogin,206logout,207/** Waits for the connection to WA to reach a state */208waitForConnectionUpdate: (0, Utils_1.bindWaitForConnectionUpdate)(ev)209};210};211exports.default = makeAuthSocket;212213214