Path: blob/master/node_modules/@adiwajshing/baileys/lib/LegacySocket/auth.js
2593 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 || Utils_1.newLegacyAuthCreds();14const state = {15legacy: {16phoneConnected: false,17},18connection: 'connecting',19};20const socket = 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');69let qrGens = 0;70const qrLoop = ttl => {71const qr = [ref, publicKey, authInfo.clientID].join(',');72updateState({ qr });73initTimeout = setTimeout(async () => {74var _a;75if (state.connection !== 'connecting') {76return;77}78logger.debug('regenerating QR');79try {80// request new QR81const { ref: newRef, ttl: newTTL } = await socket.query({82json: ['admin', 'Conn', 'reref'],83expect200: true,84longTag: true,85requiresPhoneConnection: false86});87ttl = newTTL;88ref = newRef;89}90catch (error) {91logger.error({ error }, 'error in QR gen');92if (((_a = error.output) === null || _a === void 0 ? void 0 : _a.statusCode) === 429) { // too many QR requests93socket.end(error);94return;95}96}97qrGens += 1;98qrLoop(ttl);99}, ttl || 20000); // default is 20s, on the off-chance ttl is not present100};101qrLoop(ttl);102};103const onOpen = async () => {104var _a, _b;105const canDoLogin = canLogin();106const initQuery = (async () => {107const { ref, ttl } = await socket.query({108json: ['admin', 'init', version, browser, authInfo.clientID, true],109expect200: true,110longTag: true,111requiresPhoneConnection: false112});113if (!canDoLogin) {114generateKeysForAuth(ref, ttl);115}116})();117let loginTag;118if (canDoLogin) {119updateEncKeys();120// if we have the info to restore a closed session121const json = [122'admin',123'login',124authInfo.clientToken,125authInfo.serverToken,126authInfo.clientID,127'takeover'128];129loginTag = socket.generateMessageTag(true);130// send login every 10s131const sendLoginReq = () => {132if (state.connection === 'open') {133logger.warn('Received login timeout req when state=open, ignoring...');134return;135}136logger.info('sending login request');137socket.sendNode({138json,139tag: loginTag140});141initTimeout = setTimeout(sendLoginReq, 10000);142};143sendLoginReq();144}145await initQuery;146// wait for response with tag "s1"147let response = await Promise.race([148socket.waitForMessage('s1', false, undefined).promise,149...(loginTag ? [socket.waitForMessage(loginTag, false, connectTimeoutMs).promise] : [])150]);151initTimeout && clearTimeout(initTimeout);152initTimeout = undefined;153if (response.status && response.status !== 200) {154throw new boom_1.Boom('Unexpected error in login', { data: response, statusCode: response.status });155}156// if its a challenge request (we get it when logging in)157if ((_a = response[1]) === null || _a === void 0 ? void 0 : _a.challenge) {158const json = Utils_1.computeChallengeResponse(response[1].challenge, authInfo);159logger.info('resolving login challenge');160await socket.query({ json, expect200: true, timeoutMs: connectTimeoutMs });161response = await socket.waitForMessage('s2', true).promise;162}163if (!response || !response[1]) {164throw new boom_1.Boom('Received unexpected login response', { data: response });165}166if (response[1].type === 'upgrade_md_prod') {167throw new boom_1.Boom('Require multi-device edition', { statusCode: Types_1.DisconnectReason.multideviceMismatch });168}169// validate the new connection170const { user, auth } = Utils_1.validateNewConnection(response[1], authInfo, curveKeys); // validate the connection171const isNewLogin = user.id !== ((_b = state.legacy.user) === null || _b === void 0 ? void 0 : _b.id);172Object.assign(authInfo, auth);173updateEncKeys();174logger.info({ user }, 'logged in');175ev.emit('creds.update', auth);176updateState({177connection: 'open',178legacy: {179phoneConnected: true,180user,181},182isNewLogin,183qr: undefined184});185};186ws.once('open', async () => {187try {188await onOpen();189}190catch (error) {191socket.end(error);192}193});194if (printQRInTerminal) {195Utils_1.printQRIfNecessaryListener(ev, logger);196}197process.nextTick(() => {198ev.emit('connection.update', {199...state200});201});202return {203...socket,204state,205authInfo,206ev,207canLogin,208logout,209/** Waits for the connection to WA to reach a state */210waitForConnectionUpdate: Utils_1.bindWaitForConnectionUpdate(ev)211};212};213exports.default = makeAuthSocket;214215216