diff --git a/CHANGELOG.md b/CHANGELOG.md
index 383282ce..b8f25542 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,17 @@
-# 2.3.1 (develop)
+# 2.3.2 (2025-09-02)
+
+### Features
+
+* Add support to socks proxy
+
+### Fixed
+
+* Added key id into webhook payload in n8n service
+* Enhance RabbitMQ controller with improved connection management and shutdown procedures
+* Convert outgoing images to JPEG before sending with Chatwoot
+* Update baileys dependency to version 6.7.19
+
+# 2.3.1 (2025-07-29)
### Feature
diff --git a/README.md b/README.md
index 9ad5fa0a..6d9b3344 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-[]
+[](https://hub.docker.com/r/evoapicloud/evolution-api)
[](https://evolution-api.com/whatsapp)
[](https://evolution-api.com/discord)
[](https://evolution-api.com/postman)
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 1bdd557c..b049f00f 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -1,83 +1,75 @@
+version: "3.8"
+
services:
-
api:
container_name: evolution_api
image: evoapicloud/evolution-api:latest
restart: always
depends_on:
- redis
- - postgres
+ - evolution-postgres
ports:
- - 8080:8080
+ - "127.0.0.1:8080:8080"
volumes:
- evolution_instances:/evolution/instances
networks:
- evolution-net
+ - dokploy-network
env_file:
- .env
expose:
- - 8080
+ - "8080"
redis:
+ container_name: evolution_redis
image: redis:latest
- networks:
- - evolution-net
- container_name: redis
+ restart: always
command: >
redis-server --port 6379 --appendonly yes
volumes:
- evolution_redis:/data
- ports:
- - 6379:6379
+ networks:
+ evolution-net:
+ aliases:
+ - evolution-redis
+ dokploy-network:
+ aliases:
+ - evolution-redis
+ expose:
+ - "6379"
- postgres:
- container_name: postgres
+ evolution-postgres:
+ container_name: evolution_postgres
image: postgres:15
+ restart: always
+ env_file:
+ - .env
+ command:
+ - postgres
+ - -c
+ - max_connections=1000
+ - -c
+ - listen_addresses=*
+ environment:
+ - POSTGRES_DB=${POSTGRES_DATABASE}
+ - POSTGRES_USER=${POSTGRES_USERNAME}
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
networks:
- evolution-net
- command: [
- "postgres",
- "-c", "max_connections=200",
- "-c", "listen_addresses=*",
- "-c", "shared_buffers=256MB",
- "-c", "effective_cache_size=1GB",
- "-c", "work_mem=4MB"
- ]
- restart: always
- ports:
- - 5432:5432
- environment:
- - POSTGRES_USER=user
- - POSTGRES_PASSWORD=pass
- - POSTGRES_DB=evolution_db
- - POSTGRES_HOST_AUTH_METHOD=trust
- volumes:
- - postgres_data:/var/lib/postgresql/data
-
- # pgbouncer:
- # image: edoburu/pgbouncer:latest
- # environment:
- # DB_HOST: postgres
- # DB_USER: user
- # DB_PASSWORD: pass
- # POOL_MODE: transaction
- # AUTH_TYPE: trust
- # MAX_CLIENT_CONN: 1000
- # DEFAULT_POOL_SIZE: 25
- # depends_on:
- # - postgres
- # ports:
- # - "6543:5432"
- # networks:
- # - evolution-net
+ - dokploy-network
+ expose:
+ - "5432"
volumes:
evolution_instances:
evolution_redis:
postgres_data:
-
networks:
evolution-net:
name: evolution-net
driver: bridge
+ dokploy-network:
+ external: true
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index bb9f0c48..fd6942a6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -60,6 +60,7 @@
"sharp": "^0.34.2",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
+ "socks-proxy-agent": "^8.0.5",
"swagger-ui-express": "^5.0.1",
"tsup": "^8.3.5"
},
@@ -4985,8 +4986,8 @@
}
},
"node_modules/baileys": {
- "version": "6.7.18",
- "resolved": "git+ssh://git@github.com/WhiskeySockets/Baileys.git#b7876da2e5d8d4d4b391e215b48b668517b86f3e",
+ "version": "6.7.19",
+ "resolved": "git+ssh://git@github.com/WhiskeySockets/Baileys.git#9e04cce8d3eeb16025283a57849cc83aa26c6dd1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -7739,6 +7740,19 @@
"node": ">= 0.4"
}
},
+ "node_modules/ip-address": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+ "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+ "license": "MIT",
+ "dependencies": {
+ "jsbn": "1.1.0",
+ "sprintf-js": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/ipaddr.js": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
@@ -8249,6 +8263,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsbn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
+ "license": "MIT"
+ },
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -10761,6 +10781,16 @@
"node": ">=8"
}
},
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
"node_modules/socket.io": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
@@ -10897,6 +10927,34 @@
}
}
},
+ "node_modules/socks": {
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz",
+ "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==",
+ "license": "MIT",
+ "dependencies": {
+ "ip-address": "^9.0.5",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
+ "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "socks": "^2.8.3"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/sonic-boom": {
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz",
@@ -10921,6 +10979,12 @@
"node": ">= 10.x"
}
},
+ "node_modules/sprintf-js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
diff --git a/package.json b/package.json
index 9de9d07c..107cca49 100644
--- a/package.json
+++ b/package.json
@@ -100,6 +100,7 @@
"sharp": "^0.34.2",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
+ "socks-proxy-agent": "^8.0.5",
"swagger-ui-express": "^5.0.1",
"tsup": "^8.3.5"
},
diff --git a/prisma/mysql-schema.prisma b/prisma/mysql-schema.prisma
index 33d09d2b..70efea47 100644
--- a/prisma/mysql-schema.prisma
+++ b/prisma/mysql-schema.prisma
@@ -647,22 +647,22 @@ model IsOnWhatsapp {
model N8n {
id String @id @default(cuid())
- enabled Boolean @default(true) @db.Boolean
+ enabled Boolean @default(true) @db.TinyInt(1)
description String? @db.VarChar(255)
webhookUrl String? @db.VarChar(255)
basicAuthUser String? @db.VarChar(255)
basicAuthPass String? @db.VarChar(255)
expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100)
- delayMessage Int? @db.Integer
+ delayMessage Int? @db.Int
unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false)
- debounceTime Int? @db.Integer
+ debounceTime Int? @db.Int
ignoreJids Json?
splitMessages Boolean? @default(false)
- timePerChar Int? @default(50) @db.Integer
+ timePerChar Int? @default(50) @db.Int
triggerType TriggerType?
triggerOperator TriggerOperator?
triggerValue String?
@@ -677,15 +677,15 @@ model N8nSetting {
id String @id @default(cuid())
expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100)
- delayMessage Int? @db.Integer
+ delayMessage Int? @db.Int
unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false)
- debounceTime Int? @db.Integer
+ debounceTime Int? @db.Int
ignoreJids Json?
splitMessages Boolean? @default(false)
- timePerChar Int? @default(50) @db.Integer
+ timePerChar Int? @default(50) @db.Int
createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
Fallback N8n? @relation(fields: [n8nIdFallback], references: [id])
@@ -696,21 +696,21 @@ model N8nSetting {
model Evoai {
id String @id @default(cuid())
- enabled Boolean @default(true) @db.Boolean
+ enabled Boolean @default(true) @db.TinyInt(1)
description String? @db.VarChar(255)
agentUrl String? @db.VarChar(255)
apiKey String? @db.VarChar(255)
expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100)
- delayMessage Int? @db.Integer
+ delayMessage Int? @db.Int
unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false)
- debounceTime Int? @db.Integer
+ debounceTime Int? @db.Int
ignoreJids Json?
splitMessages Boolean? @default(false)
- timePerChar Int? @default(50) @db.Integer
+ timePerChar Int? @default(50) @db.Int
triggerType TriggerType?
triggerOperator TriggerOperator?
triggerValue String?
@@ -725,15 +725,15 @@ model EvoaiSetting {
id String @id @default(cuid())
expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100)
- delayMessage Int? @db.Integer
+ delayMessage Int? @db.Int
unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false)
- debounceTime Int? @db.Integer
+ debounceTime Int? @db.Int
ignoreJids Json?
splitMessages Boolean? @default(false)
- timePerChar Int? @default(50) @db.Integer
+ timePerChar Int? @default(50) @db.Int
createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp
Fallback Evoai? @relation(fields: [evoaiIdFallback], references: [id])
diff --git a/prisma/postgresql-migrations/20250116001415_add_wavoip_token_to_settings_table/migration.sql b/prisma/postgresql-migrations/20250116001415_add_wavoip_token_to_settings_table/migration.sql
index 26898a08..00f9bc7d 100644
--- a/prisma/postgresql-migrations/20250116001415_add_wavoip_token_to_settings_table/migration.sql
+++ b/prisma/postgresql-migrations/20250116001415_add_wavoip_token_to_settings_table/migration.sql
@@ -6,14 +6,4 @@ Warnings:
*/
-- AlterTable
-DO $$
-BEGIN
- IF NOT EXISTS (
- SELECT 1
- FROM information_schema.columns
- WHERE table_name = 'Setting'
- AND column_name = 'wavoipToken'
- ) THEN
- ALTER TABLE "Setting" ADD COLUMN "wavoipToken" VARCHAR(100);
- END IF;
-END $$;
\ No newline at end of file
+ALTER TABLE "Setting" ADD COLUMN IF NOT EXISTS "wavoipToken" VARCHAR(100);
diff --git a/src/api/controllers/proxy.controller.ts b/src/api/controllers/proxy.controller.ts
index fac00375..b6e7d153 100644
--- a/src/api/controllers/proxy.controller.ts
+++ b/src/api/controllers/proxy.controller.ts
@@ -53,15 +53,21 @@ export class ProxyController {
httpsAgent: makeProxyAgent(proxy),
});
- return response?.data !== serverIp?.data;
- } catch (error) {
- if (axios.isAxiosError(error) && error.response?.data) {
- logger.error('testProxy error: ' + error.response.data);
- } else if (axios.isAxiosError(error)) {
- logger.error('testProxy error: ');
+ const result = response?.data !== serverIp?.data;
+ if (result) {
+ logger.info('testProxy: proxy connection successful');
} else {
- logger.error('testProxy error: ');
+ logger.warn("testProxy: proxy connection doesn't change the origin IP");
}
+
+ return result;
+ } catch (error) {
+ if (axios.isAxiosError(error)) {
+ logger.error('testProxy error: axios error: ' + error.message);
+ } else {
+ logger.error('testProxy error: unexpected error: ' + error);
+ }
+
return false;
}
}
diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
index 758a5bf9..c70ab6f6 100644
--- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
+++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
@@ -1446,16 +1446,7 @@ export class BaileysStartupService extends ChannelStartupService {
}
}
- const findMessage = await this.prismaRepository.message.findFirst({
- where: { instanceId: this.instanceId, key: { path: ['id'], equals: key.id } },
- });
-
- if (!findMessage) {
- continue;
- }
-
const message: any = {
- messageId: findMessage.id,
keyId: key.id,
remoteJid: key?.remoteJid,
fromMe: key.fromMe,
@@ -1465,6 +1456,16 @@ export class BaileysStartupService extends ChannelStartupService {
instanceId: this.instanceId,
};
+ let findMessage: any;
+ const configDatabaseData = this.configService.get('DATABASE').SAVE_DATA;
+ if (configDatabaseData.HISTORIC || configDatabaseData.NEW_MESSAGE) {
+ findMessage = await this.prismaRepository.message.findFirst({
+ where: { instanceId: this.instanceId, key: { path: ['id'], equals: key.id } },
+ });
+
+ if (findMessage) message.messageId = findMessage.id;
+ }
+
if (update.message === null && update.status === undefined) {
this.sendDataWebhook(Events.MESSAGES_DELETE, key);
@@ -1480,7 +1481,9 @@ export class BaileysStartupService extends ChannelStartupService {
}
continue;
- } else if (update.status !== undefined && status[update.status] !== findMessage.status) {
+ }
+
+ if (findMessage && update.status !== undefined && status[update.status] !== findMessage.status) {
if (!key.fromMe && key.remoteJid) {
readChatToUpdate[key.remoteJid] = true;
@@ -2445,9 +2448,43 @@ export class BaileysStartupService extends ChannelStartupService {
try {
const type = mediaMessage.mediatype === 'ptv' ? 'video' : mediaMessage.mediatype;
+ let mediaInput: any;
+ if (mediaMessage.mediatype === 'image') {
+ let imageBuffer: Buffer;
+ if (isURL(mediaMessage.media)) {
+ let config: any = { responseType: 'arraybuffer' };
+
+ if (this.localProxy?.enabled) {
+ config = {
+ ...config,
+ httpsAgent: makeProxyAgent({
+ host: this.localProxy.host,
+ port: this.localProxy.port,
+ protocol: this.localProxy.protocol,
+ username: this.localProxy.username,
+ password: this.localProxy.password,
+ }),
+ };
+ }
+
+ const response = await axios.get(mediaMessage.media, config);
+ imageBuffer = Buffer.from(response.data, 'binary');
+ } else {
+ imageBuffer = Buffer.from(mediaMessage.media, 'base64');
+ }
+
+ mediaInput = await sharp(imageBuffer).jpeg().toBuffer();
+ mediaMessage.fileName ??= 'image.jpg';
+ mediaMessage.mimetype = 'image/jpeg';
+ } else {
+ mediaInput = isURL(mediaMessage.media)
+ ? { url: mediaMessage.media }
+ : Buffer.from(mediaMessage.media, 'base64');
+ }
+
const prepareMedia = await prepareWAMessageMedia(
{
- [type]: isURL(mediaMessage.media) ? { url: mediaMessage.media } : Buffer.from(mediaMessage.media, 'base64'),
+ [type]: mediaInput,
} as any,
{ upload: this.client.waUploadToServer },
);
@@ -2461,7 +2498,7 @@ export class BaileysStartupService extends ChannelStartupService {
}
if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) {
- mediaMessage.fileName = 'image.png';
+ mediaMessage.fileName = 'image.jpg';
}
if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) {
@@ -3438,17 +3475,20 @@ export class BaileysStartupService extends ChannelStartupService {
where: { id: message.id },
data: { key: { ...existingKey, deleted: true }, status: 'DELETED' },
});
- const messageUpdate: any = {
- messageId: message.id,
- keyId: messageId,
- remoteJid: response.key.remoteJid,
- fromMe: response.key.fromMe,
- participant: response.key?.remoteJid,
- status: 'DELETED',
- instanceId: this.instanceId,
- };
- await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
+ if (this.configService.get('DATABASE').SAVE_DATA.MESSAGE_UPDATE) {
+ const messageUpdate: any = {
+ messageId: message.id,
+ keyId: messageId,
+ remoteJid: response.key.remoteJid,
+ fromMe: response.key.fromMe,
+ participant: response.key?.remoteJid,
+ status: 'DELETED',
+ instanceId: this.instanceId,
+ };
+ await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
+ }
} else {
+ if (!message) return response;
await this.prismaRepository.message.deleteMany({ where: { id: message.id } });
}
this.sendDataWebhook(Events.MESSAGES_DELETE, {
@@ -3780,6 +3820,10 @@ export class BaileysStartupService extends ChannelStartupService {
private async formatUpdateMessage(data: UpdateMessageDto) {
try {
+ if (!this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE) {
+ return data;
+ }
+
const msg: any = await this.getMessage(data.key, true);
if (msg?.messageType === 'conversation' || msg?.messageType === 'extendedTextMessage') {
@@ -3813,13 +3857,15 @@ export class BaileysStartupService extends ChannelStartupService {
try {
const oldMessage: any = await this.getMessage(data.key, true);
- if (!oldMessage) throw new NotFoundException('Message not found');
- if (oldMessage?.key?.remoteJid !== jid) {
- throw new BadRequestException('RemoteJid does not match');
- }
- if (oldMessage?.messageTimestamp > Date.now() + 900000) {
- // 15 minutes in milliseconds
- throw new BadRequestException('Message is older than 15 minutes');
+ if (this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE) {
+ if (!oldMessage) throw new NotFoundException('Message not found');
+ if (oldMessage?.key?.remoteJid !== jid) {
+ throw new BadRequestException('RemoteJid does not match');
+ }
+ if (oldMessage?.messageTimestamp > Date.now() + 900000) {
+ // 15 minutes in milliseconds
+ throw new BadRequestException('Message is older than 15 minutes');
+ }
}
const messageSent = await this.client.sendMessage(jid, { ...(options as any), edit: data.key });
@@ -3837,7 +3883,7 @@ export class BaileysStartupService extends ChannelStartupService {
);
const messageId = messageSent.message?.protocolMessage?.key?.id;
- if (messageId) {
+ if (messageId && this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE) {
let message = await this.prismaRepository.message.findFirst({
where: { key: { path: ['id'], equals: messageId } },
});
@@ -3849,6 +3895,7 @@ export class BaileysStartupService extends ChannelStartupService {
if ((message.key.valueOf() as any)?.deleted) {
new BadRequestException('You cannot edit deleted messages');
}
+
if (oldMessage.messageType === 'conversation' || oldMessage.messageType === 'extendedTextMessage') {
oldMessage.message.conversation = data.text;
} else {
@@ -3862,16 +3909,19 @@ export class BaileysStartupService extends ChannelStartupService {
messageTimestamp: Math.floor(Date.now() / 1000), // Convert to int32 by dividing by 1000 to get seconds
},
});
- const messageUpdate: any = {
- messageId: message.id,
- keyId: messageId,
- remoteJid: messageSent.key.remoteJid,
- fromMe: messageSent.key.fromMe,
- participant: messageSent.key?.remoteJid,
- status: 'EDITED',
- instanceId: this.instanceId,
- };
- await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
+
+ if (this.configService.get('DATABASE').SAVE_DATA.MESSAGE_UPDATE) {
+ const messageUpdate: any = {
+ messageId: message.id,
+ keyId: messageId,
+ remoteJid: messageSent.key.remoteJid,
+ fromMe: messageSent.key.fromMe,
+ participant: messageSent.key?.remoteJid,
+ status: 'EDITED',
+ instanceId: this.instanceId,
+ };
+ await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
+ }
}
}
}
diff --git a/src/api/integrations/chatbot/n8n/services/n8n.service.ts b/src/api/integrations/chatbot/n8n/services/n8n.service.ts
index 2d0802b9..5bb40890 100644
--- a/src/api/integrations/chatbot/n8n/services/n8n.service.ts
+++ b/src/api/integrations/chatbot/n8n/services/n8n.service.ts
@@ -49,6 +49,7 @@ export class N8nService extends BaseChatbotService {
sessionId: session.sessionId,
remoteJid: remoteJid,
pushName: pushName,
+ keyId: msg?.key?.id,
fromMe: msg?.key?.fromMe,
instanceName: instance.instanceName,
serverUrl: this.configService.get('SERVER').URL,
diff --git a/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts
index be73b157..3295b12d 100644
--- a/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts
+++ b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts
@@ -45,7 +45,7 @@ export class RabbitmqController extends EventController implements EventControll
heartbeat: 30, // Add heartbeat of 30 seconds
};
- amqp.connect(connectionOptions, (error, connection) => {
+ amqp.connect(connectionOptions, (error: Error, connection: amqp.Connection) => {
if (error) {
this.logger.error({
local: 'RabbitmqController.connect',
@@ -57,7 +57,7 @@ export class RabbitmqController extends EventController implements EventControll
}
// Connection event handlers
- connection.on('error', (err) => {
+ connection.on('error', (err: Error) => {
this.logger.error({
local: 'RabbitmqController.connectionError',
message: 'RabbitMQ connection error',
@@ -71,7 +71,7 @@ export class RabbitmqController extends EventController implements EventControll
this.handleConnectionLoss();
});
- connection.createChannel((channelError, channel) => {
+ connection.createChannel((channelError: Error, channel: amqp.Channel) => {
if (channelError) {
this.logger.error({
local: 'RabbitmqController.createChannel',
@@ -83,7 +83,7 @@ export class RabbitmqController extends EventController implements EventControll
}
// Channel event handlers
- channel.on('error', (err) => {
+ channel.on('error', (err: Error) => {
this.logger.error({
local: 'RabbitmqController.channelError',
message: 'RabbitMQ channel error',
@@ -136,8 +136,7 @@ export class RabbitmqController extends EventController implements EventControll
return; // Already attempting to reconnect
}
- this.amqpChannel = null;
- this.amqpConnection = null;
+ this.cleanup();
this.scheduleReconnect();
}
@@ -406,4 +405,25 @@ export class RabbitmqController extends EventController implements EventControll
}
}
}
+
+ public async cleanup(): Promise {
+ try {
+ if (this.amqpChannel) {
+ await this.amqpChannel.close();
+ this.amqpChannel = null;
+ }
+ if (this.amqpConnection) {
+ await this.amqpConnection.close();
+ this.amqpConnection = null;
+ }
+ } catch (error) {
+ this.logger.warn({
+ local: 'RabbitmqController.cleanup',
+ message: 'Error during cleanup',
+ error: error.message || error,
+ });
+ this.amqpChannel = null;
+ this.amqpConnection = null;
+ }
+ }
}
diff --git a/src/api/integrations/event/websocket/websocket.controller.ts b/src/api/integrations/event/websocket/websocket.controller.ts
index a1cef2db..3f4afd9b 100644
--- a/src/api/integrations/event/websocket/websocket.controller.ts
+++ b/src/api/integrations/event/websocket/websocket.controller.ts
@@ -30,8 +30,12 @@ export class WebsocketController extends EventController implements EventControl
const url = new URL(req.url || '', 'http://localhost');
const params = new URLSearchParams(url.search);
+ const { remoteAddress } = req.socket;
+ const isLocalhost =
+ remoteAddress === '127.0.0.1' || remoteAddress === '::1' || remoteAddress === '::ffff:127.0.0.1';
+
// Permite conexões internas do Socket.IO (EIO=4 é o Engine.IO v4)
- if (params.has('EIO')) {
+ if (params.has('EIO') && isLocalhost) {
return callback(null, true);
}
diff --git a/src/utils/makeProxyAgent.ts b/src/utils/makeProxyAgent.ts
index dcf560f6..3b1379bd 100644
--- a/src/utils/makeProxyAgent.ts
+++ b/src/utils/makeProxyAgent.ts
@@ -1,4 +1,5 @@
import { HttpsProxyAgent } from 'https-proxy-agent';
+import { SocksProxyAgent } from 'socks-proxy-agent';
type Proxy = {
host: string;
@@ -8,9 +9,28 @@ type Proxy = {
username?: string;
};
-export function makeProxyAgent(proxy: Proxy | string) {
+function selectProxyAgent(proxyUrl: string): HttpsProxyAgent | SocksProxyAgent {
+ const url = new URL(proxyUrl);
+
+ // NOTE: The following constants are not used in the function but are defined for clarity.
+ // When a proxy URL is used to build the URL object, the protocol returned by procotol's property contains a `:` at
+ // the end so, we add the protocol constants without the `:` to avoid confusion.
+ const PROXY_HTTP_PROTOCOL = 'http:';
+ const PROXY_SOCKS_PROTOCOL = 'socks:';
+
+ switch (url.protocol) {
+ case PROXY_HTTP_PROTOCOL:
+ return new HttpsProxyAgent(url);
+ case PROXY_SOCKS_PROTOCOL:
+ return new SocksProxyAgent(url);
+ default:
+ throw new Error(`Unsupported proxy protocol: ${url.protocol}`);
+ }
+}
+
+export function makeProxyAgent(proxy: Proxy | string): HttpsProxyAgent | SocksProxyAgent {
if (typeof proxy === 'string') {
- return new HttpsProxyAgent(proxy);
+ return selectProxyAgent(proxy);
}
const { host, password, port, protocol, username } = proxy;
@@ -19,5 +39,6 @@ export function makeProxyAgent(proxy: Proxy | string) {
if (username && password) {
proxyUrl = `${protocol}://${username}:${password}@${host}:${port}`;
}
- return new HttpsProxyAgent(proxyUrl);
+
+ return selectProxyAgent(proxyUrl);
}