diff --git a/src/controller/messageController.ts b/src/controller/messageController.ts index e39b2a3789..20f1d44279 100644 --- a/src/controller/messageController.ts +++ b/src/controller/messageController.ts @@ -16,7 +16,7 @@ import { Request, Response } from 'express'; -import { unlinkAsync } from '../util/functions'; +import { callSocket, unlinkAsync } from '../util/functions'; function returnError(req: Request, res: Response, error: any) { req.logger.error(error); @@ -99,7 +99,11 @@ export async function sendMessage(req: Request, res: Response) { if (results.length === 0) return res.status(400).json('Error sending message'); - req.io.emit('mensagem-enviada', results); + + /** + * Deprecated event 'mensagem-enviada' + */ + callSocket(req, ['mensagem-enviada', 'sent-message'], results); returnSucess(res, results); } catch (error) { returnError(req, res, error); @@ -856,7 +860,13 @@ export async function replyMessage(req: Request, res: Response) { if (results.length === 0) return res.status(400).json('Error sending message'); - req.io.emit('mensagem-enviada', { message: message, to: phone }); + /** + * Deprecated event 'mensagem-enviada' + */ + callSocket(req, ['mensagem-enviada', 'sent-message'], { + message: message, + to: phone, + }); returnSucess(res, results); } catch (error) { returnError(req, res, error); diff --git a/src/controller/sessionController.ts b/src/controller/sessionController.ts index 8814fe38e9..db1ec14992 100644 --- a/src/controller/sessionController.ts +++ b/src/controller/sessionController.ts @@ -23,7 +23,7 @@ import { Logger } from 'winston'; import { version } from '../../package.json'; import config from '../config'; import CreateSessionUtil from '../util/createSessionUtil'; -import { callWebHook, contactToArray } from '../util/functions'; +import { callSocket, callWebHook, contactToArray } from '../util/functions'; import getAllTokens from '../util/getAllTokens'; import { clientsArray, deleteSessionOnArray } from '../util/sessionUtil'; @@ -243,7 +243,8 @@ export async function closeSession(req: Request, res: Response) { (clientsArray as any)[session] = { status: null }; await req.client.close(); - req.io.emit('whatsapp-status', false); + + callSocket(req, 'whatsapp-status', false); callWebHook(req.client, req, 'closesession', { message: `Session: ${session} disconnected`, connected: false, @@ -300,7 +301,7 @@ export async function logOutSession(req: Request, res: Response) { }); } - req.io.emit('whatsapp-status', false); + callSocket(req, 'whatsapp-status', false); callWebHook(req.client, req, 'logoutsession', { message: `Session: ${session} logged out`, connected: false, diff --git a/src/index.ts b/src/index.ts index 329f1639b2..d2df3718dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,7 @@ import { Logger } from 'winston'; import { version } from '../package.json'; import config from './config'; import { convert } from './mapper/index'; +import { verifyTokenSocket } from './middleware/auth'; import routes from './routes'; import { ServerOptions } from './types/ServerOptions'; import { @@ -74,7 +75,7 @@ export function initServer(serverOptions: Partial): { app.use((req: any, res: any, next: NextFunction) => { req.serverOptions = serverOptions; req.logger = logger; - req.io = io as any; + req.io = io; const oldSend = res.send; @@ -107,12 +108,15 @@ export function initServer(serverOptions: Partial): { origin: '*', }, }); + io.use(verifyTokenSocket); io.on('connection', (sock) => { - logger.info(`ID: ${sock.id} entrou`); - sock.on('disconnect', () => { - logger.info(`ID: ${sock.id} saiu`); + logger.info( + `ID: ${sock.id} has disconnected. Session: ${ + sock.handshake.auth?.session || 'Unknown' + }` + ); }); }); diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts index 2a41e5b2f7..567c21b11d 100644 --- a/src/middleware/auth.ts +++ b/src/middleware/auth.ts @@ -15,7 +15,10 @@ */ import bcrypt from 'bcrypt'; import { NextFunction, Request, Response } from 'express'; +import { Socket } from 'socket.io'; +import { logger } from '..'; +import config from '../config'; import { clientsArray } from '../util/sessionUtil'; function formatSession(session: string) { @@ -89,4 +92,51 @@ const verifyToken = (req: Request, res: Response, next: NextFunction) => { } }; +export const verifyTokenSocket = (socket: Socket, next: any) => { + const secureToken = config.secretKey; + const { token, session } = socket.handshake.auth; + if (!session || !token) + return next(new Error('Session or token not informed')); + + try { + let tokenDecrypt = ''; + let sessionDecrypt = ''; + + try { + sessionDecrypt = session.split(':')[0]; + tokenDecrypt = token.split(':')[1].replace(/_/g, '/').replace(/-/g, '+'); + } catch (error) { + try { + if (token && token !== '' && token.split(' ').length > 0) { + const token_value = token.split(' ')[0]; + if (token_value) + tokenDecrypt = token_value.replace(/_/g, '/').replace(/-/g, '+'); + else tokenDecrypt = token; + } else { + tokenDecrypt = token; + } + } catch (e) { + logger.error(e); + return next(new Error('Check that a Session and Token are correct')); + } + } + bcrypt.compare( + sessionDecrypt + secureToken, + tokenDecrypt, + function (err, result) { + if (result) { + socket.join(session); + logger.info(`ID: ${socket.id} joined the channel ${session}`); + return next(); + } else { + return next(new Error('Check that a Session and Token are correct')); + } + } + ); + } catch (error) { + logger.error(error); + return next(new Error('Check that a Session and Token are correct')); + } +}; + export default verifyToken; diff --git a/src/util/createSessionUtil.ts b/src/util/createSessionUtil.ts index 116dc7f6aa..4f8bfa150a 100644 --- a/src/util/createSessionUtil.ts +++ b/src/util/createSessionUtil.ts @@ -19,7 +19,7 @@ import { Request } from 'express'; import { download } from '../controller/sessionController'; import { WhatsAppServer } from '../types/WhatsAppServer'; import chatWootClient from './chatWootClient'; -import { autoDownload, callWebHook, startHelper } from './functions'; +import { autoDownload, callSocket, callWebHook, startHelper } from './functions'; import { clientsArray, eventEmitter } from './sessionUtil'; import Factory from './tokenStore/factory'; @@ -101,6 +101,10 @@ export default class CreateSessionUtil { client.close(); clientsArray[session] = undefined; } + callSocket(req, 'status-find', { + status: statusFind, + session: client.session, + }); callWebHook(client, req, 'status-find', { status: statusFind, session: client.session, @@ -159,7 +163,7 @@ export default class CreateSessionUtil { qrCode = qrCode.replace('data:image/png;base64,', ''); const imageBuffer = Buffer.from(qrCode, 'base64'); - req.io.emit('qrCode', { + callSocket(req, ['qrCode', 'qr-code'], { data: 'data:image/png;base64,' + imageBuffer.toString('base64'), session: client.session, }); @@ -259,14 +263,18 @@ export default class CreateSessionUtil { async listenAcks(client: WhatsAppServer, req: Request) { await client.onAck(async (ack) => { - req.io.emit('onack', ack); + callSocket(req, ['onack', 'on-ack'], ack); callWebHook(client, req, 'onack', ack); }); } async onPresenceChanged(client: WhatsAppServer, req: Request) { await client.onPresenceChanged(async (presenceChangedEvent) => { - req.io.emit('onpresencechanged', presenceChangedEvent); + callSocket( + req, + ['onpresencechanged', 'on-presence-changed'], + presenceChangedEvent + ); callWebHook(client, req, 'onpresencechanged', presenceChangedEvent); }); } @@ -274,7 +282,7 @@ export default class CreateSessionUtil { async onReactionMessage(client: WhatsAppServer, req: Request) { await client.isConnected(); await client.onReactionMessage(async (reaction: any) => { - req.io.emit('onreactionmessage', reaction); + callSocket(req, ['onreactionmessage', 'on-reaction-message'], reaction); callWebHook(client, req, 'onreactionmessage', reaction); }); } @@ -282,7 +290,7 @@ export default class CreateSessionUtil { async onRevokedMessage(client: WhatsAppServer, req: Request) { await client.isConnected(); await client.onRevokedMessage(async (response: any) => { - req.io.emit('onrevokedmessage', response); + callSocket(req, ['onrevokedmessage', 'on-revoked-message'], response); callWebHook(client, req, 'onrevokedmessage', response); }); } @@ -296,7 +304,7 @@ export default class CreateSessionUtil { async onLabelUpdated(client: WhatsAppServer, req: Request) { await client.isConnected(); await client.onUpdateLabel(async (response: any) => { - req.io.emit('onupdatelabel', response); + callSocket(req, ['onupdatelabel', 'on-update-label'], response); callWebHook(client, req, 'onupdatelabel', response); }); } diff --git a/src/util/functions.ts b/src/util/functions.ts index 13dddfb669..4f79f31c27 100644 --- a/src/util/functions.ts +++ b/src/util/functions.ts @@ -109,6 +109,19 @@ export function groupNameToArray(group: any) { return localArr; } +export function callSocket(req: any, event: string | string[], data: any) { + event = Array.isArray(event) ? event : [event]; + const session = req?.session || data?.session; + + const listeners = req.io?.sockets?.adapter?.rooms?.get(session)?.size || 0; + + if (listeners == 0) return; + for (const evt of event) { + req.io.to(session).emit(evt, data); + } + return; +} + export async function callWebHook( client: any, req: Request,