Skip to content

Commit 170109a

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into develop
# Conflicts: # src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
2 parents 3601e55 + 2ded197 commit 170109a

File tree

14 files changed

+175
-104
lines changed

14 files changed

+175
-104
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ RABBITMQ_EVENTS_MESSAGES_EDITED=false
6262
RABBITMQ_EVENTS_MESSAGES_UPDATE=false
6363
RABBITMQ_EVENTS_MESSAGES_DELETE=false
6464
RABBITMQ_EVENTS_SEND_MESSAGE=false
65+
RABBITMQ_EVENTS_SEND_MESSAGE_UPDATE=false
6566
RABBITMQ_EVENTS_CONTACTS_SET=false
6667
RABBITMQ_EVENTS_CONTACTS_UPSERT=false
6768
RABBITMQ_EVENTS_CONTACTS_UPDATE=false
@@ -108,6 +109,7 @@ PUSHER_EVENTS_MESSAGES_EDITED=true
108109
PUSHER_EVENTS_MESSAGES_UPDATE=true
109110
PUSHER_EVENTS_MESSAGES_DELETE=true
110111
PUSHER_EVENTS_SEND_MESSAGE=true
112+
PUSHER_EVENTS_SEND_MESSAGE_UPDATE=true
111113
PUSHER_EVENTS_CONTACTS_SET=true
112114
PUSHER_EVENTS_CONTACTS_UPSERT=true
113115
PUSHER_EVENTS_CONTACTS_UPDATE=true
@@ -149,6 +151,7 @@ WEBHOOK_EVENTS_MESSAGES_EDITED=true
149151
WEBHOOK_EVENTS_MESSAGES_UPDATE=true
150152
WEBHOOK_EVENTS_MESSAGES_DELETE=true
151153
WEBHOOK_EVENTS_SEND_MESSAGE=true
154+
WEBHOOK_EVENTS_SEND_MESSAGE_UPDATE=true
152155
WEBHOOK_EVENTS_CONTACTS_SET=true
153156
WEBHOOK_EVENTS_CONTACTS_UPSERT=true
154157
WEBHOOK_EVENTS_CONTACTS_UPDATE=true

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 2.2.4 (hotfix)
2+
3+
### Fixed
4+
5+
* Shell injection vulnerability
6+
17
# 2.2.3 (2025-02-03 11:52)
28

39
### Fixed

Docker/swarm/evolution_api_v2.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ services:
3434
- RABBITMQ_EVENTS_MESSAGES_UPDATE=false
3535
- RABBITMQ_EVENTS_MESSAGES_DELETE=false
3636
- RABBITMQ_EVENTS_SEND_MESSAGE=false
37+
- RABBITMQ_EVENTS_SEND_MESSAGE_UPDATE=false
3738
- RABBITMQ_EVENTS_CONTACTS_SET=false
3839
- RABBITMQ_EVENTS_CONTACTS_UPSERT=false
3940
- RABBITMQ_EVENTS_CONTACTS_UPDATE=false
@@ -71,6 +72,7 @@ services:
7172
- WEBHOOK_EVENTS_MESSAGES_UPDATE=true
7273
- WEBHOOK_EVENTS_MESSAGES_DELETE=true
7374
- WEBHOOK_EVENTS_SEND_MESSAGE=true
75+
- WEBHOOK_EVENTS_SEND_MESSAGE_UPDATE=true
7476
- WEBHOOK_EVENTS_CONTACTS_SET=true
7577
- WEBHOOK_EVENTS_CONTACTS_UPSERT=true
7678
- WEBHOOK_EVENTS_CONTACTS_UPDATE=true

src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Lines changed: 119 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,39 +1135,39 @@ export class BaileysStartupService extends ChannelStartupService {
11351135
const editedMessage =
11361136
received?.message?.protocolMessage || received?.message?.editedMessage?.message?.protocolMessage;
11371137

1138-
if (received.message?.protocolMessage?.editedMessage || received.message?.editedMessage?.message) {
1139-
if (editedMessage) {
1140-
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot?.enabled)
1141-
this.chatwootService.eventWhatsapp(
1142-
'messages.edit',
1143-
{ instanceName: this.instance.name, instanceId: this.instance.id },
1144-
editedMessage,
1145-
);
1138+
if (received.message?.protocolMessage?.editedMessage && editedMessage) {
1139+
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot?.enabled)
1140+
this.chatwootService.eventWhatsapp(
1141+
'messages.edit',
1142+
{ instanceName: this.instance.name, instanceId: this.instance.id },
1143+
editedMessage,
1144+
);
11461145

1147-
await this.sendDataWebhook(Events.MESSAGES_EDITED, editedMessage);
1148-
const oldMessage = await this.getMessage(editedMessage.key, true);
1149-
if ((oldMessage as any)?.id) {
1150-
await this.prismaRepository.message.update({
1151-
where: { id: (oldMessage as any).id },
1152-
data: {
1153-
message: editedMessage.editedMessage as any,
1154-
messageTimestamp: typeof editedMessage.timestampMs === 'number'
1155-
? editedMessage.timestampMs
1156-
: (editedMessage.timestampMs as any).toNumber(),
1157-
status: 'EDITED',
1158-
},
1159-
});
1160-
await this.prismaRepository.messageUpdate.create({
1161-
data: {
1162-
fromMe: editedMessage.key.fromMe,
1163-
keyId: editedMessage.key.id,
1164-
remoteJid: editedMessage.key.remoteJid,
1165-
status: 'EDITED',
1166-
instanceId: this.instanceId,
1167-
messageId: (oldMessage as any).id,
1168-
},
1169-
});
1170-
}
1146+
await this.sendDataWebhook(Events.MESSAGES_EDITED, editedMessage);
1147+
const oldMessage = await this.getMessage(editedMessage.key, true);
1148+
if ((oldMessage as any)?.id) {
1149+
const editedMessageTimestamp = Long.isLong(editedMessage?.timestampMs)
1150+
? editedMessage.timestampMs?.toNumber()
1151+
: (editedMessage.timestampMs as number);
1152+
1153+
await this.prismaRepository.message.update({
1154+
where: { id: (oldMessage as any).id },
1155+
data: {
1156+
message: editedMessage.editedMessage as any,
1157+
messageTimestamp: editedMessageTimestamp,
1158+
status: 'EDITED',
1159+
},
1160+
});
1161+
await this.prismaRepository.messageUpdate.create({
1162+
data: {
1163+
fromMe: editedMessage.key.fromMe,
1164+
keyId: editedMessage.key.id,
1165+
remoteJid: editedMessage.key.remoteJid,
1166+
status: 'EDITED',
1167+
instanceId: this.instanceId,
1168+
messageId: (oldMessage as any).id,
1169+
},
1170+
});
11711171
}
11721172
}
11731173

@@ -1225,7 +1225,9 @@ export class BaileysStartupService extends ChannelStartupService {
12251225
existingChat &&
12261226
received.pushName &&
12271227
existingChat.name !== received.pushName &&
1228-
received.pushName.trim().length > 0
1228+
received.pushName.trim().length > 0 &&
1229+
!received.key.fromMe &&
1230+
!received.key.remoteJid.includes('@g.us')
12291231
) {
12301232
this.sendDataWebhook(Events.CHATS_UPSERT, [{ ...existingChat, name: received.pushName }]);
12311233
if (this.configService.get<Database>('DATABASE').SAVE_DATA.CHATS) {
@@ -1331,7 +1333,12 @@ export class BaileysStartupService extends ChannelStartupService {
13311333

13321334
const { buffer, mediaType, fileName, size } = media;
13331335
const mimetype = mimeTypes.lookup(fileName).toString();
1334-
const fullName = join(`${this.instance.id}`, received.key.remoteJid, mediaType, fileName);
1336+
const fullName = join(
1337+
`${this.instance.id}`,
1338+
received.key.remoteJid,
1339+
mediaType,
1340+
`${Date.now()}_${fileName}`,
1341+
);
13351342
await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, {
13361343
'Content-Type': mimetype,
13371344
});
@@ -1579,7 +1586,6 @@ export class BaileysStartupService extends ChannelStartupService {
15791586
const chatToInsert = {
15801587
remoteJid: message.remoteJid,
15811588
instanceId: this.instanceId,
1582-
name: message.pushName || '',
15831589
unreadMessages: 0,
15841590
};
15851591

@@ -2753,15 +2759,35 @@ export class BaileysStartupService extends ChannelStartupService {
27532759
imageBuffer = Buffer.from(response.data, 'binary');
27542760
}
27552761

2756-
const webpBuffer = await sharp(imageBuffer).webp().toBuffer();
2762+
const isAnimated = this.isAnimated(image, imageBuffer);
27572763

2758-
return webpBuffer;
2764+
if (isAnimated) {
2765+
return await sharp(imageBuffer, { animated: true }).webp({ quality: 80 }).toBuffer();
2766+
} else {
2767+
return await sharp(imageBuffer).webp().toBuffer();
2768+
}
27592769
} catch (error) {
27602770
console.error('Erro ao converter a imagem para WebP:', error);
27612771
throw error;
27622772
}
27632773
}
27642774

2775+
private isAnimatedWebp(buffer: Buffer): boolean {
2776+
if (buffer.length < 12) return false;
2777+
2778+
return buffer.indexOf(Buffer.from('ANIM')) !== -1;
2779+
}
2780+
2781+
private isAnimated(image: string, buffer: Buffer): boolean {
2782+
const lowerCaseImage = image.toLowerCase();
2783+
2784+
if (lowerCaseImage.includes('.gif')) return true;
2785+
2786+
if (lowerCaseImage.includes('.webp')) return this.isAnimatedWebp(buffer);
2787+
2788+
return false;
2789+
}
2790+
27652791
public async mediaSticker(data: SendStickerDto, file?: any) {
27662792
const mediaData: SendStickerDto = { ...data };
27672793

@@ -3973,71 +3999,71 @@ export class BaileysStartupService extends ChannelStartupService {
39733999
throw new BadRequestException('Message is older than 15 minutes');
39744000
}
39754001

3976-
const response = await this.client.sendMessage(jid, {
4002+
const messageSent = await this.client.sendMessage(jid, {
39774003
...(options as any),
39784004
edit: data.key,
39794005
});
3980-
if (response) {
3981-
const messageId = response.message?.protocolMessage?.key?.id;
3982-
if (messageId) {
3983-
let message = await this.prismaRepository.message.findFirst({
3984-
where: {
3985-
key: {
3986-
path: ['id'],
3987-
equals: messageId,
4006+
if (messageSent) {
4007+
const editedMessage =
4008+
messageSent?.message?.protocolMessage || messageSent?.message?.editedMessage?.message?.protocolMessage;
4009+
4010+
if (editedMessage) {
4011+
this.sendDataWebhook(Events.SEND_MESSAGE_UPDATE, editedMessage);
4012+
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot?.enabled)
4013+
this.chatwootService.eventWhatsapp(
4014+
'send.message.update',
4015+
{ instanceName: this.instance.name, instanceId: this.instance.id },
4016+
editedMessage,
4017+
);
4018+
4019+
const messageId = messageSent.message?.protocolMessage?.key?.id;
4020+
if (messageId) {
4021+
let message = await this.prismaRepository.message.findFirst({
4022+
where: {
4023+
key: {
4024+
path: ['id'],
4025+
equals: messageId,
4026+
},
39884027
},
3989-
},
3990-
});
3991-
if (!message) throw new NotFoundException('Message not found');
4028+
});
4029+
if (!message) throw new NotFoundException('Message not found');
39924030

3993-
if (!(message.key.valueOf() as any).fromMe) {
3994-
new BadRequestException('You cannot edit others messages');
3995-
}
3996-
if ((message.key.valueOf() as any)?.deleted) {
3997-
new BadRequestException('You cannot edit deleted messages');
3998-
}
3999-
if (oldMessage.messageType === 'conversation' || oldMessage.messageType === 'extendedTextMessage') {
4000-
oldMessage.message.conversation = data.text;
4001-
} else {
4002-
oldMessage.message[oldMessage.messageType].caption = data.text;
4003-
}
4004-
message = await this.prismaRepository.message.update({
4005-
where: { id: message.id },
4006-
data: {
4007-
message: oldMessage.message,
4031+
if (!(message.key.valueOf() as any).fromMe) {
4032+
new BadRequestException('You cannot edit others messages');
4033+
}
4034+
if ((message.key.valueOf() as any)?.deleted) {
4035+
new BadRequestException('You cannot edit deleted messages');
4036+
}
4037+
if (oldMessage.messageType === 'conversation' || oldMessage.messageType === 'extendedTextMessage') {
4038+
oldMessage.message.conversation = data.text;
4039+
} else {
4040+
oldMessage.message[oldMessage.messageType].caption = data.text;
4041+
}
4042+
message = await this.prismaRepository.message.update({
4043+
where: { id: message.id },
4044+
data: {
4045+
message: oldMessage.message,
4046+
status: 'EDITED',
4047+
messageTimestamp: Math.floor(Date.now() / 1000), // Convert to int32 by dividing by 1000 to get seconds
4048+
},
4049+
});
4050+
const messageUpdate: any = {
4051+
messageId: message.id,
4052+
keyId: messageId,
4053+
remoteJid: messageSent.key.remoteJid,
4054+
fromMe: messageSent.key.fromMe,
4055+
participant: messageSent.key?.remoteJid,
40084056
status: 'EDITED',
4009-
messageTimestamp: Math.floor(Date.now() / 1000), // Convert to int32 by dividing by 1000 to get seconds
4010-
},
4011-
});
4012-
const messageUpdate: any = {
4013-
messageId: message.id,
4014-
keyId: messageId,
4015-
remoteJid: response.key.remoteJid,
4016-
fromMe: response.key.fromMe,
4017-
participant: response.key?.remoteJid,
4018-
status: 'EDITED',
4019-
instanceId: this.instanceId,
4020-
};
4021-
await this.prismaRepository.messageUpdate.create({
4022-
data: messageUpdate,
4023-
});
4024-
4025-
this.sendDataWebhook(Events.MESSAGES_EDITED, {
4026-
id: message.id,
4027-
instanceId: message.instanceId,
4028-
key: message.key,
4029-
messageType: message.messageType,
4030-
status: 'EDITED',
4031-
source: message.source,
4032-
messageTimestamp: message.messageTimestamp,
4033-
pushName: message.pushName,
4034-
participant: message.participant,
4035-
message: message.message,
4036-
});
4057+
instanceId: this.instanceId,
4058+
};
4059+
await this.prismaRepository.messageUpdate.create({
4060+
data: messageUpdate,
4061+
});
4062+
}
40374063
}
40384064
}
40394065

4040-
return response;
4066+
return messageSent;
40414067
} catch (error) {
40424068
this.logger.error(error);
40434069
throw error;

src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2218,7 +2218,7 @@ export class ChatwootService {
22182218
}
22192219
}
22202220

2221-
if (event === 'messages.edit') {
2221+
if (event === 'messages.edit' || event === 'send.message.update') {
22222222
const editedText = `${
22232223
body?.editedMessage?.conversation || body?.editedMessage?.extendedTextMessage?.text
22242224
}\n\n_\`${i18next.t('cw.message.edited')}.\`_`;

src/api/integrations/event/event.controller.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ export class EventController {
132132
'MESSAGES_UPDATE',
133133
'MESSAGES_DELETE',
134134
'SEND_MESSAGE',
135+
'SEND_MESSAGE_UPDATE',
135136
'CONTACTS_SET',
136137
'CONTACTS_UPSERT',
137138
'CONTACTS_UPDATE',

src/api/integrations/storage/s3/libs/minio.server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ const createBucket = async () => {
6363
if (!exists) {
6464
await minioClient.makeBucket(bucketName);
6565
}
66-
67-
await setBucketPolicy();
68-
66+
if (!BUCKET.SKIP_POLICY) {
67+
await setBucketPolicy();
68+
}
6969
logger.info(`S3 Bucket ${bucketName} - ON`);
7070
return true;
7171
} catch (error) {

src/api/provider/sessions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Auth, ConfigService, ProviderSession } from '@config/env.config';
22
import { Logger } from '@config/logger.config';
33
import axios from 'axios';
4-
import { execSync } from 'child_process';
4+
import { execFileSync } from 'child_process';
55

66
type ResponseSuccess = { status: number; data?: any };
77
type ResponseProvider = Promise<[ResponseSuccess?, Error?]>;
@@ -36,7 +36,7 @@ export class ProviderFiles {
3636
} catch (error) {
3737
this.logger.error(['Failed to connect to the file server', error?.message, error?.stack]);
3838
const pid = process.pid;
39-
execSync(`kill -9 ${pid}`);
39+
execFileSync('kill', ['-9', `${pid}`]);
4040
}
4141
}
4242
}

0 commit comments

Comments
 (0)