mobile connection

This commit is contained in:
Davidson Gomes 2024-04-08 19:09:59 -03:00
parent 240f01f378
commit 1172b6c871
6 changed files with 127 additions and 10 deletions

View File

@ -46,7 +46,7 @@
"@figuro/chatwoot-sdk": "^1.1.16", "@figuro/chatwoot-sdk": "^1.1.16",
"@hapi/boom": "^10.0.1", "@hapi/boom": "^10.0.1",
"@sentry/node": "^7.59.2", "@sentry/node": "^7.59.2",
"@whiskeysockets/baileys": "6.6.0", "@whiskeysockets/baileys": "github:AtendAI/Baileys",
"amqplib": "^0.10.3", "amqplib": "^0.10.3",
"aws-sdk": "^2.1499.0", "aws-sdk": "^2.1499.0",
"axios": "^1.6.5", "axios": "^1.6.5",

View File

@ -53,6 +53,7 @@ export class InstanceController {
events, events,
qrcode, qrcode,
number, number,
mobile,
integration, integration,
token, token,
chatwoot_account_id, chatwoot_account_id,
@ -115,7 +116,7 @@ export class InstanceController {
); );
} }
await this.waMonitor.saveInstance({ integration, instanceName, token, number }); await this.waMonitor.saveInstance({ integration, instanceName, token, number, mobile });
instance.instanceName = instanceName; instance.instanceName = instanceName;
@ -405,7 +406,7 @@ export class InstanceController {
if (qrcode) { if (qrcode) {
this.logger.verbose('creating qrcode'); this.logger.verbose('creating qrcode');
await instance.connectToWhatsapp(number); await instance.connectToWhatsapp(number, mobile);
await delay(5000); await delay(5000);
getQrcode = instance.qrCode; getQrcode = instance.qrCode;
} }
@ -569,7 +570,7 @@ export class InstanceController {
} }
} }
public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) { public async connectToWhatsapp({ instanceName, number = null, mobile = null }: InstanceDto) {
try { try {
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance'); this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
@ -592,7 +593,7 @@ export class InstanceController {
if (state == 'close') { if (state == 'close') {
this.logger.verbose('connecting'); this.logger.verbose('connecting');
await instance.connectToWhatsapp(number); await instance.connectToWhatsapp(number, mobile);
await delay(5000); await delay(5000);
return instance.qrCode; return instance.qrCode;
@ -633,6 +634,20 @@ export class InstanceController {
} }
} }
public async registerMobileCode({ instanceName }: InstanceDto, { mobileCode }: any) {
try {
this.logger.verbose('requested registerMobileCode from ' + instanceName + ' instance');
const instance = this.waMonitor.waInstances[instanceName];
console.log('mobileCode', mobileCode);
return await instance.receiveMobileCode(mobileCode);
// return { status: 'SUCCESS', error: false, response: { message: 'Mobile code registered' } };
} catch (error) {
this.logger.error(error);
}
}
public async connectionState({ instanceName }: InstanceDto) { public async connectionState({ instanceName }: InstanceDto) {
this.logger.verbose('requested connectionState from ' + instanceName + ' instance'); this.logger.verbose('requested connectionState from ' + instanceName + ' instance');
return { return {

View File

@ -1,10 +1,11 @@
import { WAPresence } from "@whiskeysockets/baileys"; import { WAPresence } from '@whiskeysockets/baileys';
export class InstanceDto { export class InstanceDto {
instanceName: string; instanceName: string;
instanceId?: string; instanceId?: string;
qrcode?: boolean; qrcode?: boolean;
number?: string; number?: string;
mobile?: boolean;
integration?: string; integration?: string;
token?: string; token?: string;
webhook?: string; webhook?: string;

View File

@ -3,7 +3,7 @@ import { RequestHandler, Router } from 'express';
import { Auth, ConfigService, Database } from '../../config/env.config'; import { Auth, ConfigService, Database } from '../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
import {instanceNameSchema, oldTokenSchema, presenceOnlySchema} from '../../validate/validate.schema'; import { instanceNameSchema, oldTokenSchema, presenceOnlySchema } from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../abstract/abstract.router';
import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; import { InstanceDto, SetPresenceDto } from '../dto/instance.dto';
import { OldToken } from '../services/auth.service'; import { OldToken } from '../services/auth.service';
@ -50,6 +50,22 @@ export class InstanceRouter extends RouterBroker {
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('registerMobileCode'), ...guards, async (req, res) => {
logger.verbose('request received in registerMobileCode');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<null>({
request: req,
schema: instanceNameSchema,
ClassRef: SetPresenceDto,
execute: (instance, data) => instanceController.registerMobileCode(instance, data),
});
return res.status(HttpStatus.OK).json(response);
})
.get(this.routerPath('connect'), ...guards, async (req, res) => { .get(this.routerPath('connect'), ...guards, async (req, res) => {
logger.verbose('request received in connectInstance'); logger.verbose('request received in connectInstance');
logger.verbose('request body: '); logger.verbose('request body: ');

View File

@ -12,6 +12,7 @@ import makeWASocket, {
DisconnectReason, DisconnectReason,
downloadMediaMessage, downloadMediaMessage,
fetchLatestBaileysVersion, fetchLatestBaileysVersion,
generateMobileNode,
generateWAMessageFromContent, generateWAMessageFromContent,
getAggregateVotesInPollMessage, getAggregateVotesInPollMessage,
getContentType, getContentType,
@ -24,6 +25,7 @@ import makeWASocket, {
MessageUpsertType, MessageUpsertType,
MiscMessageGenerationOptions, MiscMessageGenerationOptions,
ParticipantAction, ParticipantAction,
PHONENUMBER_MCC,
prepareWAMessageMedia, prepareWAMessageMedia,
proto, proto,
useMultiFileAuthState, useMultiFileAuthState,
@ -42,6 +44,7 @@ import { exec } from 'child_process';
import { arrayUnique, isBase64, isURL } from 'class-validator'; import { arrayUnique, isBase64, isURL } from 'class-validator';
import EventEmitter2 from 'eventemitter2'; import EventEmitter2 from 'eventemitter2';
import fs, { existsSync, readFileSync } from 'fs'; import fs, { existsSync, readFileSync } from 'fs';
import { parsePhoneNumber } from 'libphonenumber-js';
import Long from 'long'; import Long from 'long';
import NodeCache from 'node-cache'; import NodeCache from 'node-cache';
import { getMIMEType } from 'node-mime-types'; import { getMIMEType } from 'node-mime-types';
@ -132,6 +135,7 @@ export class BaileysStartupService extends WAStartupService {
this.logger.verbose('BaileysStartupService initialized'); this.logger.verbose('BaileysStartupService initialized');
this.cleanStore(); this.cleanStore();
this.instance.qrcode = { count: 0 }; this.instance.qrcode = { count: 0 };
this.mobile = false;
} }
private readonly msgRetryCounterCache: CacheStore = new NodeCache(); private readonly msgRetryCounterCache: CacheStore = new NodeCache();
@ -141,7 +145,8 @@ export class BaileysStartupService extends WAStartupService {
public stateConnection: wa.StateConnection = { state: 'close' }; public stateConnection: wa.StateConnection = { state: 'close' };
private phoneNumber: string; public phoneNumber: string;
public mobile: boolean;
public get connectionStatus() { public get connectionStatus() {
this.logger.verbose('Getting connection status'); this.logger.verbose('Getting connection status');
@ -389,6 +394,10 @@ export class BaileysStartupService extends WAStartupService {
); );
} }
} }
if (connection === 'connecting') {
if (this.mobile) this.sendMobileCode();
}
} }
private async getMessage(key: proto.IMessageKey, full = false) { private async getMessage(key: proto.IMessageKey, full = false) {
@ -446,7 +455,7 @@ export class BaileysStartupService extends WAStartupService {
return await useMultiFileAuthState(join(INSTANCE_DIR, this.instance.name)); return await useMultiFileAuthState(join(INSTANCE_DIR, this.instance.name));
} }
public async connectToWhatsapp(number?: string): Promise<WASocket> { public async connectToWhatsapp(number?: string, mobile?: boolean): Promise<WASocket> {
this.logger.verbose('Connecting to whatsapp'); this.logger.verbose('Connecting to whatsapp');
try { try {
this.loadWebhook(); this.loadWebhook();
@ -461,7 +470,14 @@ export class BaileysStartupService extends WAStartupService {
this.instance.authState = await this.defineAuthState(); this.instance.authState = await this.defineAuthState();
if (!mobile) {
this.mobile = false;
} else {
this.mobile = mobile;
}
const { version } = await fetchLatestBaileysVersion(); const { version } = await fetchLatestBaileysVersion();
this.logger.verbose('Baileys version: ' + version); this.logger.verbose('Baileys version: ' + version);
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE'); const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()]; const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
@ -500,6 +516,7 @@ export class BaileysStartupService extends WAStartupService {
}, },
logger: P({ level: this.logBaileys }), logger: P({ level: this.logBaileys }),
printQRInTerminal: false, printQRInTerminal: false,
mobile,
browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser, browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser,
version, version,
markOnlineOnConnect: this.localSettings.always_online, markOnlineOnConnect: this.localSettings.always_online,
@ -564,6 +581,70 @@ export class BaileysStartupService extends WAStartupService {
} }
} }
private async sendMobileCode() {
const { registration } = this.client.authState.creds || null;
let phoneNumber = registration.phoneNumber || this.phoneNumber;
if (!phoneNumber.startsWith('+')) {
phoneNumber = '+' + phoneNumber;
}
if (!phoneNumber) {
this.logger.error('Phone number not found');
return;
}
console.log('phoneNumber', phoneNumber);
const parsedPhoneNumber = parsePhoneNumber(phoneNumber);
console.log('parsedPhoneNumber', parsedPhoneNumber);
if (!parsedPhoneNumber?.isValid()) {
this.logger.error('Phone number invalid');
return;
}
registration.phoneNumber = parsedPhoneNumber.format('E.164');
registration.phoneNumberCountryCode = parsedPhoneNumber.countryCallingCode;
registration.phoneNumberNationalNumber = parsedPhoneNumber.nationalNumber;
const mcc = await PHONENUMBER_MCC[parsedPhoneNumber.countryCallingCode];
if (!mcc) {
this.logger.error('MCC not found');
return;
}
registration.phoneNumberMobileCountryCode = mcc;
registration.method = 'voice';
try {
const response = await this.client.requestRegistrationCode(registration);
console.log('response', response);
if (['ok', 'sent'].includes(response?.status)) {
this.logger.verbose('Registration code sent successfully');
return response;
}
} catch (error) {
this.logger.error(error);
}
}
public async receiveMobileCode(code: string) {
await this.client
.register(code.replace(/["']/g, '').trim().toLowerCase())
.then(async (response) => {
this.logger.verbose('Registration code received successfully');
console.log(response);
})
.catch((error) => {
this.logger.error(error);
});
}
public async reloadConnection(): Promise<WASocket> { public async reloadConnection(): Promise<WASocket> {
try { try {
this.instance.authState = await this.defineAuthState(); this.instance.authState = await this.defineAuthState();

View File

@ -44,7 +44,8 @@ export class BusinessStartupService extends WAStartupService {
public stateConnection: wa.StateConnection = { state: 'open' }; public stateConnection: wa.StateConnection = { state: 'open' };
private phoneNumber: string; public phoneNumber: string;
public mobile: boolean;
public get connectionStatus() { public get connectionStatus() {
this.logger.verbose('Getting connection status'); this.logger.verbose('Getting connection status');
@ -1347,4 +1348,7 @@ export class BusinessStartupService extends WAStartupService {
public async handleLabel() { public async handleLabel() {
throw new BadRequestException('Method not available on WhatsApp Business API'); throw new BadRequestException('Method not available on WhatsApp Business API');
} }
public async receiveMobileCode() {
throw new BadRequestException('Method not available on WhatsApp Business API');
}
} }