Compare commits

..

No commits in common. "main" and "2.3.1" have entirely different histories.
main ... 2.3.1

13 changed files with 135 additions and 297 deletions

View File

@ -1,17 +1,4 @@
# 2.3.2 (2025-09-02) # 2.3.1 (develop)
### 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 ### Feature

View File

@ -2,7 +2,7 @@
<div align="center"> <div align="center">
[![Docker Image](https://img.shields.io/badge/Docker-image-blue)](https://hub.docker.com/r/evoapicloud/evolution-api) [![Docker Image (https://img.shields.io/badge/Docker-Image-blue)](https://hub.docker.com/r/evoapicloud/evolution-api)]
[![Whatsapp Group](https://img.shields.io/badge/Group-WhatsApp-%2322BC18)](https://evolution-api.com/whatsapp) [![Whatsapp Group](https://img.shields.io/badge/Group-WhatsApp-%2322BC18)](https://evolution-api.com/whatsapp)
[![Discord Community](https://img.shields.io/badge/Discord-Community-blue)](https://evolution-api.com/discord) [![Discord Community](https://img.shields.io/badge/Discord-Community-blue)](https://evolution-api.com/discord)
[![Postman Collection](https://img.shields.io/badge/Postman-Collection-orange)](https://evolution-api.com/postman) [![Postman Collection](https://img.shields.io/badge/Postman-Collection-orange)](https://evolution-api.com/postman)

View File

@ -1,75 +1,83 @@
version: "3.8"
services: services:
api: api:
container_name: evolution_api container_name: evolution_api
image: evoapicloud/evolution-api:latest image: evoapicloud/evolution-api:latest
restart: always restart: always
depends_on: depends_on:
- redis - redis
- evolution-postgres - postgres
ports: ports:
- "127.0.0.1:8080:8080" - 8080:8080
volumes: volumes:
- evolution_instances:/evolution/instances - evolution_instances:/evolution/instances
networks: networks:
- evolution-net - evolution-net
- dokploy-network
env_file: env_file:
- .env - .env
expose: expose:
- "8080" - 8080
redis: redis:
container_name: evolution_redis
image: redis:latest image: redis:latest
restart: always networks:
- evolution-net
container_name: redis
command: > command: >
redis-server --port 6379 --appendonly yes redis-server --port 6379 --appendonly yes
volumes: volumes:
- evolution_redis:/data - evolution_redis:/data
networks: ports:
evolution-net: - 6379:6379
aliases:
- evolution-redis
dokploy-network:
aliases:
- evolution-redis
expose:
- "6379"
evolution-postgres: postgres:
container_name: evolution_postgres container_name: postgres
image: postgres:15 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: networks:
- evolution-net - evolution-net
- dokploy-network command: [
expose: "postgres",
- "5432" "-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
volumes: volumes:
evolution_instances: evolution_instances:
evolution_redis: evolution_redis:
postgres_data: postgres_data:
networks: networks:
evolution-net: evolution-net:
name: evolution-net name: evolution-net
driver: bridge driver: bridge
dokploy-network:
external: true

72
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "evolution-api", "name": "evolution-api",
"version": "2.3.2", "version": "2.3.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "evolution-api", "name": "evolution-api",
"version": "2.3.2", "version": "2.3.1",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@adiwajshing/keyed-db": "^0.2.4", "@adiwajshing/keyed-db": "^0.2.4",
@ -60,7 +60,6 @@
"sharp": "^0.34.2", "sharp": "^0.34.2",
"socket.io": "^4.8.1", "socket.io": "^4.8.1",
"socket.io-client": "^4.8.1", "socket.io-client": "^4.8.1",
"socks-proxy-agent": "^8.0.5",
"swagger-ui-express": "^5.0.1", "swagger-ui-express": "^5.0.1",
"tsup": "^8.3.5" "tsup": "^8.3.5"
}, },
@ -4986,8 +4985,8 @@
} }
}, },
"node_modules/baileys": { "node_modules/baileys": {
"version": "6.7.19", "version": "6.7.18",
"resolved": "git+ssh://git@github.com/WhiskeySockets/Baileys.git#9e04cce8d3eeb16025283a57849cc83aa26c6dd1", "resolved": "git+ssh://git@github.com/WhiskeySockets/Baileys.git#b7876da2e5d8d4d4b391e215b48b668517b86f3e",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -7740,19 +7739,6 @@
"node": ">= 0.4" "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": { "node_modules/ipaddr.js": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
@ -8263,12 +8249,6 @@
"js-yaml": "bin/js-yaml.js" "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": { "node_modules/json-buffer": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@ -10781,16 +10761,6 @@
"node": ">=8" "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": { "node_modules/socket.io": {
"version": "4.8.1", "version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
@ -10927,34 +10897,6 @@
} }
} }
}, },
"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": { "node_modules/sonic-boom": {
"version": "3.8.1", "version": "3.8.1",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz",
@ -10979,12 +10921,6 @@
"node": ">= 10.x" "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": { "node_modules/statuses": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "evolution-api", "name": "evolution-api",
"version": "2.3.2", "version": "2.3.1",
"description": "Rest api for communication with WhatsApp", "description": "Rest api for communication with WhatsApp",
"main": "./dist/main.js", "main": "./dist/main.js",
"type": "commonjs", "type": "commonjs",
@ -100,7 +100,6 @@
"sharp": "^0.34.2", "sharp": "^0.34.2",
"socket.io": "^4.8.1", "socket.io": "^4.8.1",
"socket.io-client": "^4.8.1", "socket.io-client": "^4.8.1",
"socks-proxy-agent": "^8.0.5",
"swagger-ui-express": "^5.0.1", "swagger-ui-express": "^5.0.1",
"tsup": "^8.3.5" "tsup": "^8.3.5"
}, },

View File

@ -647,22 +647,22 @@ model IsOnWhatsapp {
model N8n { model N8n {
id String @id @default(cuid()) id String @id @default(cuid())
enabled Boolean @default(true) @db.TinyInt(1) enabled Boolean @default(true) @db.Boolean
description String? @db.VarChar(255) description String? @db.VarChar(255)
webhookUrl String? @db.VarChar(255) webhookUrl String? @db.VarChar(255)
basicAuthUser String? @db.VarChar(255) basicAuthUser String? @db.VarChar(255)
basicAuthPass String? @db.VarChar(255) basicAuthPass String? @db.VarChar(255)
expire Int? @default(0) @db.Int expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100) keywordFinish String? @db.VarChar(100)
delayMessage Int? @db.Int delayMessage Int? @db.Integer
unknownMessage String? @db.VarChar(100) unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false) listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false) stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false) keepOpen Boolean? @default(false)
debounceTime Int? @db.Int debounceTime Int? @db.Integer
ignoreJids Json? ignoreJids Json?
splitMessages Boolean? @default(false) splitMessages Boolean? @default(false)
timePerChar Int? @default(50) @db.Int timePerChar Int? @default(50) @db.Integer
triggerType TriggerType? triggerType TriggerType?
triggerOperator TriggerOperator? triggerOperator TriggerOperator?
triggerValue String? triggerValue String?
@ -677,15 +677,15 @@ model N8nSetting {
id String @id @default(cuid()) id String @id @default(cuid())
expire Int? @default(0) @db.Int expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100) keywordFinish String? @db.VarChar(100)
delayMessage Int? @db.Int delayMessage Int? @db.Integer
unknownMessage String? @db.VarChar(100) unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false) listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false) stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false) keepOpen Boolean? @default(false)
debounceTime Int? @db.Int debounceTime Int? @db.Integer
ignoreJids Json? ignoreJids Json?
splitMessages Boolean? @default(false) splitMessages Boolean? @default(false)
timePerChar Int? @default(50) @db.Int timePerChar Int? @default(50) @db.Integer
createdAt DateTime? @default(now()) @db.Timestamp createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp
Fallback N8n? @relation(fields: [n8nIdFallback], references: [id]) Fallback N8n? @relation(fields: [n8nIdFallback], references: [id])
@ -696,21 +696,21 @@ model N8nSetting {
model Evoai { model Evoai {
id String @id @default(cuid()) id String @id @default(cuid())
enabled Boolean @default(true) @db.TinyInt(1) enabled Boolean @default(true) @db.Boolean
description String? @db.VarChar(255) description String? @db.VarChar(255)
agentUrl String? @db.VarChar(255) agentUrl String? @db.VarChar(255)
apiKey String? @db.VarChar(255) apiKey String? @db.VarChar(255)
expire Int? @default(0) @db.Int expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100) keywordFinish String? @db.VarChar(100)
delayMessage Int? @db.Int delayMessage Int? @db.Integer
unknownMessage String? @db.VarChar(100) unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false) listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false) stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false) keepOpen Boolean? @default(false)
debounceTime Int? @db.Int debounceTime Int? @db.Integer
ignoreJids Json? ignoreJids Json?
splitMessages Boolean? @default(false) splitMessages Boolean? @default(false)
timePerChar Int? @default(50) @db.Int timePerChar Int? @default(50) @db.Integer
triggerType TriggerType? triggerType TriggerType?
triggerOperator TriggerOperator? triggerOperator TriggerOperator?
triggerValue String? triggerValue String?
@ -725,15 +725,15 @@ model EvoaiSetting {
id String @id @default(cuid()) id String @id @default(cuid())
expire Int? @default(0) @db.Int expire Int? @default(0) @db.Int
keywordFinish String? @db.VarChar(100) keywordFinish String? @db.VarChar(100)
delayMessage Int? @db.Int delayMessage Int? @db.Integer
unknownMessage String? @db.VarChar(100) unknownMessage String? @db.VarChar(100)
listeningFromMe Boolean? @default(false) listeningFromMe Boolean? @default(false)
stopBotFromMe Boolean? @default(false) stopBotFromMe Boolean? @default(false)
keepOpen Boolean? @default(false) keepOpen Boolean? @default(false)
debounceTime Int? @db.Int debounceTime Int? @db.Integer
ignoreJids Json? ignoreJids Json?
splitMessages Boolean? @default(false) splitMessages Boolean? @default(false)
timePerChar Int? @default(50) @db.Int timePerChar Int? @default(50) @db.Integer
createdAt DateTime? @default(now()) @db.Timestamp createdAt DateTime? @default(now()) @db.Timestamp
updatedAt DateTime @updatedAt @db.Timestamp updatedAt DateTime @updatedAt @db.Timestamp
Fallback Evoai? @relation(fields: [evoaiIdFallback], references: [id]) Fallback Evoai? @relation(fields: [evoaiIdFallback], references: [id])

View File

@ -6,4 +6,14 @@ Warnings:
*/ */
-- AlterTable -- AlterTable
ALTER TABLE "Setting" ADD COLUMN IF NOT EXISTS "wavoipToken" VARCHAR(100); 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 $$;

View File

@ -53,21 +53,15 @@ export class ProxyController {
httpsAgent: makeProxyAgent(proxy), httpsAgent: makeProxyAgent(proxy),
}); });
const result = response?.data !== serverIp?.data; return response?.data !== serverIp?.data;
if (result) {
logger.info('testProxy: proxy connection successful');
} else {
logger.warn("testProxy: proxy connection doesn't change the origin IP");
}
return result;
} catch (error) { } catch (error) {
if (axios.isAxiosError(error)) { if (axios.isAxiosError(error) && error.response?.data) {
logger.error('testProxy error: axios error: ' + error.message); logger.error('testProxy error: ' + error.response.data);
} else if (axios.isAxiosError(error)) {
logger.error('testProxy error: ');
} else { } else {
logger.error('testProxy error: unexpected error: ' + error); logger.error('testProxy error: ');
} }
return false; return false;
} }
} }

View File

@ -1446,7 +1446,16 @@ 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 = { const message: any = {
messageId: findMessage.id,
keyId: key.id, keyId: key.id,
remoteJid: key?.remoteJid, remoteJid: key?.remoteJid,
fromMe: key.fromMe, fromMe: key.fromMe,
@ -1456,16 +1465,6 @@ export class BaileysStartupService extends ChannelStartupService {
instanceId: this.instanceId, instanceId: this.instanceId,
}; };
let findMessage: any;
const configDatabaseData = this.configService.get<Database>('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) { if (update.message === null && update.status === undefined) {
this.sendDataWebhook(Events.MESSAGES_DELETE, key); this.sendDataWebhook(Events.MESSAGES_DELETE, key);
@ -1481,9 +1480,7 @@ export class BaileysStartupService extends ChannelStartupService {
} }
continue; 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) { if (!key.fromMe && key.remoteJid) {
readChatToUpdate[key.remoteJid] = true; readChatToUpdate[key.remoteJid] = true;
@ -2448,43 +2445,9 @@ export class BaileysStartupService extends ChannelStartupService {
try { try {
const type = mediaMessage.mediatype === 'ptv' ? 'video' : mediaMessage.mediatype; 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( const prepareMedia = await prepareWAMessageMedia(
{ {
[type]: mediaInput, [type]: isURL(mediaMessage.media) ? { url: mediaMessage.media } : Buffer.from(mediaMessage.media, 'base64'),
} as any, } as any,
{ upload: this.client.waUploadToServer }, { upload: this.client.waUploadToServer },
); );
@ -2498,7 +2461,7 @@ export class BaileysStartupService extends ChannelStartupService {
} }
if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) { if (mediaMessage.mediatype === 'image' && !mediaMessage.fileName) {
mediaMessage.fileName = 'image.jpg'; mediaMessage.fileName = 'image.png';
} }
if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) { if (mediaMessage.mediatype === 'video' && !mediaMessage.fileName) {
@ -3475,20 +3438,17 @@ export class BaileysStartupService extends ChannelStartupService {
where: { id: message.id }, where: { id: message.id },
data: { key: { ...existingKey, deleted: true }, status: 'DELETED' }, data: { key: { ...existingKey, deleted: true }, status: 'DELETED' },
}); });
if (this.configService.get<Database>('DATABASE').SAVE_DATA.MESSAGE_UPDATE) { const messageUpdate: any = {
const messageUpdate: any = { messageId: message.id,
messageId: message.id, keyId: messageId,
keyId: messageId, remoteJid: response.key.remoteJid,
remoteJid: response.key.remoteJid, fromMe: response.key.fromMe,
fromMe: response.key.fromMe, participant: response.key?.remoteJid,
participant: response.key?.remoteJid, status: 'DELETED',
status: 'DELETED', instanceId: this.instanceId,
instanceId: this.instanceId, };
}; await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
}
} else { } else {
if (!message) return response;
await this.prismaRepository.message.deleteMany({ where: { id: message.id } }); await this.prismaRepository.message.deleteMany({ where: { id: message.id } });
} }
this.sendDataWebhook(Events.MESSAGES_DELETE, { this.sendDataWebhook(Events.MESSAGES_DELETE, {
@ -3820,10 +3780,6 @@ export class BaileysStartupService extends ChannelStartupService {
private async formatUpdateMessage(data: UpdateMessageDto) { private async formatUpdateMessage(data: UpdateMessageDto) {
try { try {
if (!this.configService.get<Database>('DATABASE').SAVE_DATA.NEW_MESSAGE) {
return data;
}
const msg: any = await this.getMessage(data.key, true); const msg: any = await this.getMessage(data.key, true);
if (msg?.messageType === 'conversation' || msg?.messageType === 'extendedTextMessage') { if (msg?.messageType === 'conversation' || msg?.messageType === 'extendedTextMessage') {
@ -3857,15 +3813,13 @@ export class BaileysStartupService extends ChannelStartupService {
try { try {
const oldMessage: any = await this.getMessage(data.key, true); const oldMessage: any = await this.getMessage(data.key, true);
if (this.configService.get<Database>('DATABASE').SAVE_DATA.NEW_MESSAGE) { if (!oldMessage) throw new NotFoundException('Message not found');
if (!oldMessage) throw new NotFoundException('Message not found'); if (oldMessage?.key?.remoteJid !== jid) {
if (oldMessage?.key?.remoteJid !== jid) { throw new BadRequestException('RemoteJid does not match');
throw new BadRequestException('RemoteJid does not match'); }
} if (oldMessage?.messageTimestamp > Date.now() + 900000) {
if (oldMessage?.messageTimestamp > Date.now() + 900000) { // 15 minutes in milliseconds
// 15 minutes in milliseconds throw new BadRequestException('Message is older than 15 minutes');
throw new BadRequestException('Message is older than 15 minutes');
}
} }
const messageSent = await this.client.sendMessage(jid, { ...(options as any), edit: data.key }); const messageSent = await this.client.sendMessage(jid, { ...(options as any), edit: data.key });
@ -3883,7 +3837,7 @@ export class BaileysStartupService extends ChannelStartupService {
); );
const messageId = messageSent.message?.protocolMessage?.key?.id; const messageId = messageSent.message?.protocolMessage?.key?.id;
if (messageId && this.configService.get<Database>('DATABASE').SAVE_DATA.NEW_MESSAGE) { if (messageId) {
let message = await this.prismaRepository.message.findFirst({ let message = await this.prismaRepository.message.findFirst({
where: { key: { path: ['id'], equals: messageId } }, where: { key: { path: ['id'], equals: messageId } },
}); });
@ -3895,7 +3849,6 @@ export class BaileysStartupService extends ChannelStartupService {
if ((message.key.valueOf() as any)?.deleted) { if ((message.key.valueOf() as any)?.deleted) {
new BadRequestException('You cannot edit deleted messages'); new BadRequestException('You cannot edit deleted messages');
} }
if (oldMessage.messageType === 'conversation' || oldMessage.messageType === 'extendedTextMessage') { if (oldMessage.messageType === 'conversation' || oldMessage.messageType === 'extendedTextMessage') {
oldMessage.message.conversation = data.text; oldMessage.message.conversation = data.text;
} else { } else {
@ -3909,19 +3862,16 @@ export class BaileysStartupService extends ChannelStartupService {
messageTimestamp: Math.floor(Date.now() / 1000), // Convert to int32 by dividing by 1000 to get seconds messageTimestamp: Math.floor(Date.now() / 1000), // Convert to int32 by dividing by 1000 to get seconds
}, },
}); });
const messageUpdate: any = {
if (this.configService.get<Database>('DATABASE').SAVE_DATA.MESSAGE_UPDATE) { messageId: message.id,
const messageUpdate: any = { keyId: messageId,
messageId: message.id, remoteJid: messageSent.key.remoteJid,
keyId: messageId, fromMe: messageSent.key.fromMe,
remoteJid: messageSent.key.remoteJid, participant: messageSent.key?.remoteJid,
fromMe: messageSent.key.fromMe, status: 'EDITED',
participant: messageSent.key?.remoteJid, instanceId: this.instanceId,
status: 'EDITED', };
instanceId: this.instanceId, await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
};
await this.prismaRepository.messageUpdate.create({ data: messageUpdate });
}
} }
} }
} }

View File

@ -49,7 +49,6 @@ export class N8nService extends BaseChatbotService<N8n, N8nSetting> {
sessionId: session.sessionId, sessionId: session.sessionId,
remoteJid: remoteJid, remoteJid: remoteJid,
pushName: pushName, pushName: pushName,
keyId: msg?.key?.id,
fromMe: msg?.key?.fromMe, fromMe: msg?.key?.fromMe,
instanceName: instance.instanceName, instanceName: instance.instanceName,
serverUrl: this.configService.get<HttpServer>('SERVER').URL, serverUrl: this.configService.get<HttpServer>('SERVER').URL,

View File

@ -45,7 +45,7 @@ export class RabbitmqController extends EventController implements EventControll
heartbeat: 30, // Add heartbeat of 30 seconds heartbeat: 30, // Add heartbeat of 30 seconds
}; };
amqp.connect(connectionOptions, (error: Error, connection: amqp.Connection) => { amqp.connect(connectionOptions, (error, connection) => {
if (error) { if (error) {
this.logger.error({ this.logger.error({
local: 'RabbitmqController.connect', local: 'RabbitmqController.connect',
@ -57,7 +57,7 @@ export class RabbitmqController extends EventController implements EventControll
} }
// Connection event handlers // Connection event handlers
connection.on('error', (err: Error) => { connection.on('error', (err) => {
this.logger.error({ this.logger.error({
local: 'RabbitmqController.connectionError', local: 'RabbitmqController.connectionError',
message: 'RabbitMQ connection error', message: 'RabbitMQ connection error',
@ -71,7 +71,7 @@ export class RabbitmqController extends EventController implements EventControll
this.handleConnectionLoss(); this.handleConnectionLoss();
}); });
connection.createChannel((channelError: Error, channel: amqp.Channel) => { connection.createChannel((channelError, channel) => {
if (channelError) { if (channelError) {
this.logger.error({ this.logger.error({
local: 'RabbitmqController.createChannel', local: 'RabbitmqController.createChannel',
@ -83,7 +83,7 @@ export class RabbitmqController extends EventController implements EventControll
} }
// Channel event handlers // Channel event handlers
channel.on('error', (err: Error) => { channel.on('error', (err) => {
this.logger.error({ this.logger.error({
local: 'RabbitmqController.channelError', local: 'RabbitmqController.channelError',
message: 'RabbitMQ channel error', message: 'RabbitMQ channel error',
@ -136,7 +136,8 @@ export class RabbitmqController extends EventController implements EventControll
return; // Already attempting to reconnect return; // Already attempting to reconnect
} }
this.cleanup(); this.amqpChannel = null;
this.amqpConnection = null;
this.scheduleReconnect(); this.scheduleReconnect();
} }
@ -405,25 +406,4 @@ export class RabbitmqController extends EventController implements EventControll
} }
} }
} }
public async cleanup(): Promise<void> {
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;
}
}
} }

View File

@ -30,12 +30,8 @@ export class WebsocketController extends EventController implements EventControl
const url = new URL(req.url || '', 'http://localhost'); const url = new URL(req.url || '', 'http://localhost');
const params = new URLSearchParams(url.search); 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) // Permite conexões internas do Socket.IO (EIO=4 é o Engine.IO v4)
if (params.has('EIO') && isLocalhost) { if (params.has('EIO')) {
return callback(null, true); return callback(null, true);
} }

View File

@ -1,5 +1,4 @@
import { HttpsProxyAgent } from 'https-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent';
import { SocksProxyAgent } from 'socks-proxy-agent';
type Proxy = { type Proxy = {
host: string; host: string;
@ -9,28 +8,9 @@ type Proxy = {
username?: string; username?: string;
}; };
function selectProxyAgent(proxyUrl: string): HttpsProxyAgent<string> | SocksProxyAgent { export function makeProxyAgent(proxy: Proxy | string) {
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<string> | SocksProxyAgent {
if (typeof proxy === 'string') { if (typeof proxy === 'string') {
return selectProxyAgent(proxy); return new HttpsProxyAgent(proxy);
} }
const { host, password, port, protocol, username } = proxy; const { host, password, port, protocol, username } = proxy;
@ -39,6 +19,5 @@ export function makeProxyAgent(proxy: Proxy | string): HttpsProxyAgent<string> |
if (username && password) { if (username && password) {
proxyUrl = `${protocol}://${username}:${password}@${host}:${port}`; proxyUrl = `${protocol}://${username}:${password}@${host}:${port}`;
} }
return new HttpsProxyAgent(proxyUrl);
return selectProxyAgent(proxyUrl);
} }