@fer2809fl/baileys 1.4.7 → 1.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +352 -115
- package/lib/Baileys.jpeg +0 -0
- package/lib/Signal/Group/group_cipher.js +22 -13
- package/lib/Signal/Group/sender-key-record.js +27 -14
- package/lib/Socket/newsletter.js +1 -1
- package/lib/Socket/setup.js +3 -3
- package/lib/Socket/setup.ts +3 -3
- package/lib/Socket/socket.js +560 -0
- package/lib/Utils/auth-utils.js +23 -11
- package/lib/Utils/button-handler.js +151 -0
- package/lib/Utils/error-handler.js +37 -0
- package/lib/Utils/index.d.ts +1 -0
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/interactive.js +254 -0
- package/lib/Utils/messages.js +2 -2
- package/lib/Utils/process-message.js +43 -25
- package/lib/Utils/use-multi-file-auth-state.js +41 -21
- package/lib/WABinary/constants.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +5 -5
package/lib/Utils/auth-utils.js
CHANGED
|
@@ -131,34 +131,45 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
|
|
|
131
131
|
if (transactionsInProgress === 1) {
|
|
132
132
|
logger.trace('entering transaction');
|
|
133
133
|
}
|
|
134
|
+
|
|
134
135
|
try {
|
|
135
136
|
result = await work();
|
|
137
|
+
|
|
136
138
|
// commit if this is the outermost transaction
|
|
137
139
|
if (transactionsInProgress === 1) {
|
|
138
140
|
if (Object.keys(mutations).length) {
|
|
139
141
|
logger.trace('committing transaction');
|
|
140
|
-
|
|
141
|
-
//
|
|
142
|
+
|
|
143
|
+
// 🔧 REPARADO: Retry mechanism con backoff exponencial
|
|
142
144
|
let tries = maxCommitRetries;
|
|
143
|
-
|
|
145
|
+
let delayMs = delayBetweenTriesMs;
|
|
146
|
+
|
|
147
|
+
while (tries > 0) {
|
|
144
148
|
tries -= 1;
|
|
145
149
|
try {
|
|
146
150
|
await state.set(mutations);
|
|
147
151
|
logger.trace({ dbQueriesInTransaction }, 'committed transaction');
|
|
148
152
|
break;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (tries === 0) {
|
|
155
|
+
logger.error({ error }, `CRITICAL: Failed to commit after ${maxCommitRetries} retries`);
|
|
156
|
+
// No propagar error - evita crash del bot
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
logger.warn(`Commit failed, retries left=${tries}, waiting ${delayMs}ms`);
|
|
161
|
+
await (0, generics_1.delay)(delayMs);
|
|
162
|
+
delayMs = Math.min(delayMs * 2, 30000); // Exponential backoff, max 30s
|
|
153
163
|
}
|
|
154
164
|
}
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
165
|
+
} else {
|
|
157
166
|
logger.trace('no mutations in transaction');
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
|
-
}
|
|
161
|
-
|
|
169
|
+
} catch (workError) {
|
|
170
|
+
logger.error({ workError }, 'Error in transaction work');
|
|
171
|
+
throw workError;
|
|
172
|
+
} finally {
|
|
162
173
|
transactionsInProgress -= 1;
|
|
163
174
|
if (transactionsInProgress === 0) {
|
|
164
175
|
transactionCache = {};
|
|
@@ -166,6 +177,7 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
|
|
|
166
177
|
dbQueriesInTransaction = 0;
|
|
167
178
|
}
|
|
168
179
|
}
|
|
180
|
+
|
|
169
181
|
return result;
|
|
170
182
|
}
|
|
171
183
|
};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleButtonResponse = handleButtonResponse;
|
|
4
|
+
exports.setupButtonHandler = setupButtonHandler;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maneja las respuestas de botones y las convierte en comandos ejecutables
|
|
8
|
+
*/
|
|
9
|
+
async function handleButtonResponse(sock, m, plugins, db) {
|
|
10
|
+
|
|
11
|
+
// ========== DETECTAR SOLO BOTONES ==========
|
|
12
|
+
let seleccion = null
|
|
13
|
+
let tipoBoton = null
|
|
14
|
+
|
|
15
|
+
// Botón tipo quick_reply (interactive)
|
|
16
|
+
if (m.mtype === 'interactiveResponseMessage') {
|
|
17
|
+
const resp = m.message?.interactiveResponseMessage?.nativeFlowResponseMessage
|
|
18
|
+
if (resp?.name === 'quick_reply') {
|
|
19
|
+
seleccion = resp.id
|
|
20
|
+
tipoBoton = 'quick_reply'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Botón tipo buttonsResponse (estilo antiguo)
|
|
25
|
+
if (m.mtype === 'buttonsResponseMessage') {
|
|
26
|
+
seleccion = m.message?.buttonsResponseMessage?.selectedButtonId
|
|
27
|
+
tipoBoton = 'buttonsResponse'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Lista desplegable
|
|
31
|
+
if (m.mtype === 'listResponseMessage') {
|
|
32
|
+
seleccion = m.message?.listResponseMessage?.singleSelectReply?.selectedRowId
|
|
33
|
+
tipoBoton = 'listResponse'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Si no es botón, salir
|
|
37
|
+
if (!seleccion) return false
|
|
38
|
+
|
|
39
|
+
console.log(`[Baileys] Botón detectado [${tipoBoton}]:`, seleccion)
|
|
40
|
+
|
|
41
|
+
// Limpiar el ID del botón
|
|
42
|
+
let cmd = seleccion.toString().toLowerCase().replace(/^[.#!/]/, '').trim()
|
|
43
|
+
|
|
44
|
+
// ========== BUSCAR PLUGIN ==========
|
|
45
|
+
let pluginFound = null
|
|
46
|
+
|
|
47
|
+
for (let name in plugins) {
|
|
48
|
+
let plugin = plugins[name]
|
|
49
|
+
if (!plugin || !plugin.command) continue
|
|
50
|
+
|
|
51
|
+
let commands = Array.isArray(plugin.command) ? plugin.command : [plugin.command]
|
|
52
|
+
|
|
53
|
+
const isMatch = commands.some(c => {
|
|
54
|
+
if (c instanceof RegExp) return c.test(cmd)
|
|
55
|
+
return c.toString().toLowerCase() === cmd
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if (isMatch) {
|
|
59
|
+
pluginFound = plugin
|
|
60
|
+
break
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!pluginFound) {
|
|
65
|
+
console.log(`[Baileys] No se encontró plugin para: ${cmd}`)
|
|
66
|
+
await sock.sendMessage(m.chat, {
|
|
67
|
+
text: `❌ *Comando no encontrado*\n\nEl botón "${seleccion}" no tiene un comando asociado.`
|
|
68
|
+
}, { quoted: m })
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ========== OBTENER PERMISOS ==========
|
|
73
|
+
const groupMetadata = m.isGroup ? await sock.groupMetadata(m.chat).catch(() => null) || {} : {}
|
|
74
|
+
const participants = groupMetadata?.participants || []
|
|
75
|
+
|
|
76
|
+
const isAdmin = m.isGroup ? participants.find(p => p.id === m.sender)?.admin === 'admin' || participants.find(p => p.id === m.sender)?.admin === 'superadmin' : false
|
|
77
|
+
const isBotAdmin = m.isGroup ? participants.find(p => p.id === sock.user.id)?.admin === 'admin' || participants.find(p => p.id === sock.user.id)?.admin === 'superadmin' : false
|
|
78
|
+
const isOwner = [...global.owner || []].map(v => v + "@s.whatsapp.net").includes(m.sender)
|
|
79
|
+
|
|
80
|
+
// ========== VALIDAR PERMISOS ==========
|
|
81
|
+
if (pluginFound.rowner && !isOwner) {
|
|
82
|
+
await sock.sendMessage(m.chat, { text: `🔒 *Acceso denegado*\n\nEste comando es solo para los creadores del bot.` }, { quoted: m })
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (pluginFound.owner && !isOwner) {
|
|
87
|
+
await sock.sendMessage(m.chat, { text: `🔒 *Acceso denegado*\n\nEste comando es solo para el owner del bot.` }, { quoted: m })
|
|
88
|
+
return true
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (pluginFound.admin && !isAdmin) {
|
|
92
|
+
await sock.sendMessage(m.chat, { text: `⚠️ *Permiso denegado*\n\nEste comando solo puede ser usado por administradores del grupo.` }, { quoted: m })
|
|
93
|
+
return true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (pluginFound.botAdmin && !isBotAdmin) {
|
|
97
|
+
await sock.sendMessage(m.chat, { text: `🤖 *Bot sin permisos*\n\nNecesito ser administrador del grupo para ejecutar este comando.` }, { quoted: m })
|
|
98
|
+
return true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (pluginFound.group && !m.isGroup) {
|
|
102
|
+
await sock.sendMessage(m.chat, { text: `👥 *Solo grupos*\n\nEste comando solo puede usarse en grupos.` }, { quoted: m })
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (pluginFound.private && m.isGroup) {
|
|
107
|
+
await sock.sendMessage(m.chat, { text: `🔒 *Solo privado*\n\nEste comando solo puede usarse en chat privado.` }, { quoted: m })
|
|
108
|
+
return true
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ========== EJECUTAR PLUGIN ==========
|
|
112
|
+
try {
|
|
113
|
+
await pluginFound.call(sock, m, {
|
|
114
|
+
conn: sock,
|
|
115
|
+
usedPrefix: '',
|
|
116
|
+
command: cmd,
|
|
117
|
+
args: [],
|
|
118
|
+
text: '',
|
|
119
|
+
participants,
|
|
120
|
+
groupMetadata,
|
|
121
|
+
isAdmin,
|
|
122
|
+
isBotAdmin,
|
|
123
|
+
isOwner,
|
|
124
|
+
db
|
|
125
|
+
})
|
|
126
|
+
console.log(`[Baileys] Plugin ejecutado: ${cmd}`)
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error(`[Baileys] Error:`, error)
|
|
129
|
+
await sock.sendMessage(m.chat, { text: `❌ *Error al ejecutar el comando*\n\n${error.message || error}` }, { quoted: m })
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return true
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Configura el handler de botones en el socket
|
|
137
|
+
*/
|
|
138
|
+
function setupButtonHandler(sock, plugins, db) {
|
|
139
|
+
const originalHandler = sock.ev.listeners('messages.upsert')[0]
|
|
140
|
+
|
|
141
|
+
sock.ev.off('messages.upsert', originalHandler)
|
|
142
|
+
|
|
143
|
+
sock.ev.on('messages.upsert', async ({ messages }) => {
|
|
144
|
+
for (const m of messages) {
|
|
145
|
+
const fueBoton = await handleButtonResponse(sock, m, plugins, db)
|
|
146
|
+
if (!fueBoton && originalHandler) {
|
|
147
|
+
await originalHandler({ messages: [m] })
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.safeDecrypt = safeDecrypt;
|
|
4
|
+
exports.silenceBadMacErrors = silenceBadMacErrors;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Envuelve una función para capturar y silenciar errores Bad MAC
|
|
8
|
+
*/
|
|
9
|
+
function safeDecrypt(fn) {
|
|
10
|
+
return async (...args) => {
|
|
11
|
+
try {
|
|
12
|
+
return await fn(...args);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
if (error.message && error.message.includes('Bad MAC')) {
|
|
15
|
+
console.log('[Baileys] 🔇 Bad MAC silenciado');
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Parchea los métodos de libsignal para no mostrar errores Bad MAC
|
|
25
|
+
*/
|
|
26
|
+
function silenceBadMacErrors() {
|
|
27
|
+
const originalConsoleError = console.error;
|
|
28
|
+
console.error = (...args) => {
|
|
29
|
+
const message = args.join(' ');
|
|
30
|
+
if (message.includes('Bad MAC') ||
|
|
31
|
+
message.includes('Failed to decrypt') ||
|
|
32
|
+
message.includes('No session found')) {
|
|
33
|
+
return; // No mostrar
|
|
34
|
+
}
|
|
35
|
+
originalConsoleError(...args);
|
|
36
|
+
};
|
|
37
|
+
}
|
package/lib/Utils/index.d.ts
CHANGED
package/lib/Utils/index.js
CHANGED
|
@@ -31,3 +31,4 @@ __exportStar(require("./use-multi-file-auth-state"), exports);
|
|
|
31
31
|
__exportStar(require("./link-preview"), exports);
|
|
32
32
|
__exportStar(require("./event-buffer"), exports);
|
|
33
33
|
__exportStar(require("./process-message"), exports);
|
|
34
|
+
__exportStar(require("./interactive"), exports);
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendInteractiveMessage = exports.sendListMenu = exports.sendCallButton = exports.sendQuickReplyButtons = exports.sendUrlButton = exports.sendCopyButton = void 0;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Envía un mensaje con botón que copia texto al portapapeles
|
|
7
|
+
*/
|
|
8
|
+
async function sendCopyButton(sock, jid, text, copyText, buttonText) {
|
|
9
|
+
try {
|
|
10
|
+
await sock.sendMessage(jid, {
|
|
11
|
+
interactiveMessage: {
|
|
12
|
+
body: { text: text },
|
|
13
|
+
footer: { text: '⚡ Asta-Bot' },
|
|
14
|
+
header: {
|
|
15
|
+
title: '📋 Copiar Código',
|
|
16
|
+
hasMediaAttachment: false
|
|
17
|
+
},
|
|
18
|
+
nativeFlowMessage: {
|
|
19
|
+
buttons: [{
|
|
20
|
+
name: 'cta_copy',
|
|
21
|
+
buttonParamsJson: JSON.stringify({
|
|
22
|
+
display_text: buttonText || '📋 Copiar',
|
|
23
|
+
copy_code: copyText
|
|
24
|
+
})
|
|
25
|
+
}]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error('[interactive] Error en sendCopyButton:', error);
|
|
31
|
+
await sock.sendMessage(jid, { text: `${text}\n\n📋 Copia esto: ${copyText}` });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.sendCopyButton = sendCopyButton;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Envía un mensaje con botón de enlace (URL)
|
|
38
|
+
*/
|
|
39
|
+
async function sendUrlButton(sock, jid, text, url, buttonText) {
|
|
40
|
+
try {
|
|
41
|
+
await sock.sendMessage(jid, {
|
|
42
|
+
interactiveMessage: {
|
|
43
|
+
body: { text: text },
|
|
44
|
+
footer: { text: '⚡ Asta-Bot' },
|
|
45
|
+
header: {
|
|
46
|
+
title: '🔗 Enlace Rápido',
|
|
47
|
+
hasMediaAttachment: false
|
|
48
|
+
},
|
|
49
|
+
nativeFlowMessage: {
|
|
50
|
+
buttons: [{
|
|
51
|
+
name: 'cta_url',
|
|
52
|
+
buttonParamsJson: JSON.stringify({
|
|
53
|
+
display_text: buttonText || '🔗 Abrir Enlace',
|
|
54
|
+
url: url,
|
|
55
|
+
merchant_url: url
|
|
56
|
+
})
|
|
57
|
+
}]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error('[interactive] Error en sendUrlButton:', error);
|
|
63
|
+
await sock.sendMessage(jid, { text: `${text}\n\n🔗 Enlace: ${url}` });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.sendUrlButton = sendUrlButton;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Envía un mensaje con botones de respuesta rápida
|
|
70
|
+
*/
|
|
71
|
+
async function sendQuickReplyButtons(sock, jid, text, buttons) {
|
|
72
|
+
try {
|
|
73
|
+
const interactiveButtons = buttons.map(btn => ({
|
|
74
|
+
name: 'quick_reply',
|
|
75
|
+
buttonParamsJson: JSON.stringify({
|
|
76
|
+
display_text: btn.text,
|
|
77
|
+
id: btn.id
|
|
78
|
+
})
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
await sock.sendMessage(jid, {
|
|
82
|
+
interactiveMessage: {
|
|
83
|
+
body: { text: text },
|
|
84
|
+
footer: { text: '⚡ Asta-Bot - Selecciona una opción' },
|
|
85
|
+
header: {
|
|
86
|
+
hasMediaAttachment: false
|
|
87
|
+
},
|
|
88
|
+
nativeFlowMessage: {
|
|
89
|
+
buttons: interactiveButtons
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error('[interactive] Error en sendQuickReplyButtons:', error);
|
|
95
|
+
const buttonsText = buttons.map(b => `• ${b.text} → ${b.id}`).join('\n');
|
|
96
|
+
await sock.sendMessage(jid, { text: `${text}\n\n${buttonsText}` });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.sendQuickReplyButtons = sendQuickReplyButtons;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Envía un mensaje con botón de llamada telefónica
|
|
103
|
+
*/
|
|
104
|
+
async function sendCallButton(sock, jid, text, phoneNumber, buttonText) {
|
|
105
|
+
try {
|
|
106
|
+
await sock.sendMessage(jid, {
|
|
107
|
+
interactiveMessage: {
|
|
108
|
+
body: { text: text },
|
|
109
|
+
footer: { text: '⚡ Asta-Bot' },
|
|
110
|
+
header: {
|
|
111
|
+
title: '📞 Llamar',
|
|
112
|
+
hasMediaAttachment: false
|
|
113
|
+
},
|
|
114
|
+
nativeFlowMessage: {
|
|
115
|
+
buttons: [{
|
|
116
|
+
name: 'cta_call',
|
|
117
|
+
buttonParamsJson: JSON.stringify({
|
|
118
|
+
display_text: buttonText || '📞 Llamar Ahora',
|
|
119
|
+
phone_number: phoneNumber
|
|
120
|
+
})
|
|
121
|
+
}]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('[interactive] Error en sendCallButton:', error);
|
|
127
|
+
await sock.sendMessage(jid, { text: `${text}\n\n📞 Llama a: ${phoneNumber}` });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.sendCallButton = sendCallButton;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Envía un mensaje con lista desplegable (single select)
|
|
134
|
+
*/
|
|
135
|
+
async function sendListMenu(sock, jid, text, title, sections) {
|
|
136
|
+
try {
|
|
137
|
+
// Formatear secciones correctamente
|
|
138
|
+
const formattedSections = sections.map(section => ({
|
|
139
|
+
title: section.title,
|
|
140
|
+
rows: section.rows.map(row => ({
|
|
141
|
+
header: row.header || '',
|
|
142
|
+
title: row.title,
|
|
143
|
+
description: row.description || '',
|
|
144
|
+
id: row.id
|
|
145
|
+
}))
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
await sock.sendMessage(jid, {
|
|
149
|
+
interactiveMessage: {
|
|
150
|
+
body: { text: text },
|
|
151
|
+
footer: { text: '⚡ Asta-Bot - Menú Interactivo' },
|
|
152
|
+
header: {
|
|
153
|
+
title: title || '📋 Menú de Opciones',
|
|
154
|
+
hasMediaAttachment: false
|
|
155
|
+
},
|
|
156
|
+
nativeFlowMessage: {
|
|
157
|
+
buttons: [{
|
|
158
|
+
name: 'single_select',
|
|
159
|
+
buttonParamsJson: JSON.stringify({
|
|
160
|
+
title: '📋 Ver opciones',
|
|
161
|
+
sections: formattedSections
|
|
162
|
+
})
|
|
163
|
+
}]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error('[interactive] Error en sendListMenu:', error);
|
|
169
|
+
let fallbackText = `${text}\n\n`;
|
|
170
|
+
sections.forEach(sec => {
|
|
171
|
+
fallbackText += `\n*${sec.title}*\n`;
|
|
172
|
+
sec.rows.forEach(row => {
|
|
173
|
+
fallbackText += `• ${row.id} - ${row.title}\n`;
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
await sock.sendMessage(jid, { text: fallbackText });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.sendListMenu = sendListMenu;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Envía un mensaje con múltiples botones combinados
|
|
183
|
+
*/
|
|
184
|
+
async function sendInteractiveMessage(sock, jid, text, buttonsConfig) {
|
|
185
|
+
try {
|
|
186
|
+
const buttons = buttonsConfig.map(btn => {
|
|
187
|
+
let buttonParams = {};
|
|
188
|
+
|
|
189
|
+
switch (btn.type) {
|
|
190
|
+
case 'copy':
|
|
191
|
+
buttonParams = {
|
|
192
|
+
name: 'cta_copy',
|
|
193
|
+
buttonParamsJson: JSON.stringify({
|
|
194
|
+
display_text: btn.text,
|
|
195
|
+
copy_code: btn.value
|
|
196
|
+
})
|
|
197
|
+
};
|
|
198
|
+
break;
|
|
199
|
+
case 'url':
|
|
200
|
+
buttonParams = {
|
|
201
|
+
name: 'cta_url',
|
|
202
|
+
buttonParamsJson: JSON.stringify({
|
|
203
|
+
display_text: btn.text,
|
|
204
|
+
url: btn.value,
|
|
205
|
+
merchant_url: btn.value
|
|
206
|
+
})
|
|
207
|
+
};
|
|
208
|
+
break;
|
|
209
|
+
case 'call':
|
|
210
|
+
buttonParams = {
|
|
211
|
+
name: 'cta_call',
|
|
212
|
+
buttonParamsJson: JSON.stringify({
|
|
213
|
+
display_text: btn.text,
|
|
214
|
+
phone_number: btn.value
|
|
215
|
+
})
|
|
216
|
+
};
|
|
217
|
+
break;
|
|
218
|
+
case 'quick':
|
|
219
|
+
buttonParams = {
|
|
220
|
+
name: 'quick_reply',
|
|
221
|
+
buttonParamsJson: JSON.stringify({
|
|
222
|
+
display_text: btn.text,
|
|
223
|
+
id: btn.id || btn.value
|
|
224
|
+
})
|
|
225
|
+
};
|
|
226
|
+
break;
|
|
227
|
+
default:
|
|
228
|
+
buttonParams = {
|
|
229
|
+
name: 'quick_reply',
|
|
230
|
+
buttonParamsJson: JSON.stringify({
|
|
231
|
+
display_text: btn.text,
|
|
232
|
+
id: btn.id || btn.value
|
|
233
|
+
})
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return buttonParams;
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
await sock.sendMessage(jid, {
|
|
240
|
+
interactiveMessage: {
|
|
241
|
+
body: { text: text },
|
|
242
|
+
footer: { text: '⚡ Asta-Bot' },
|
|
243
|
+
header: {
|
|
244
|
+
hasMediaAttachment: false
|
|
245
|
+
},
|
|
246
|
+
nativeFlowMessage: { buttons }
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.error('[interactive] Error en sendInteractiveMessage:', error);
|
|
251
|
+
await sock.sendMessage(jid, { text: text });
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
exports.sendInteractiveMessage = sendInteractiveMessage;
|
package/lib/Utils/messages.js
CHANGED
|
@@ -104,9 +104,9 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
104
104
|
}
|
|
105
105
|
],
|
|
106
106
|
newsletter: {
|
|
107
|
-
newsletterJid: "
|
|
107
|
+
newsletterJid: "120363399175402285@newsletter",
|
|
108
108
|
serverMessageId: 0,
|
|
109
|
-
newsletterName: "
|
|
109
|
+
newsletterName: "Asta",
|
|
110
110
|
contentType: "UPDATE",
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -98,19 +98,31 @@ exports.getChatId = getChatId;
|
|
|
98
98
|
* @param ctx additional info about the poll required for decryption
|
|
99
99
|
* @returns list of SHA256 options
|
|
100
100
|
*/
|
|
101
|
+
// 🔧 REPARADO: Agregado try-catch completo
|
|
101
102
|
function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pollEncKey, voterJid, }) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
103
|
+
try {
|
|
104
|
+
// Validar que tenemos todos los datos necesarios
|
|
105
|
+
if (!encPayload || !encIv || !pollEncKey) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const sign = Buffer.concat([
|
|
110
|
+
toBinary(pollMsgId),
|
|
111
|
+
toBinary(pollCreatorJid),
|
|
112
|
+
toBinary(voterJid),
|
|
113
|
+
toBinary('Poll Vote'),
|
|
114
|
+
new Uint8Array([1])
|
|
115
|
+
]);
|
|
116
|
+
const key0 = (0, crypto_1.hmacSign)(pollEncKey, new Uint8Array(32), 'sha256');
|
|
117
|
+
const decKey = (0, crypto_1.hmacSign)(sign, key0, 'sha256');
|
|
118
|
+
const aad = toBinary(`${pollMsgId}\u0000${voterJid}`);
|
|
119
|
+
const decrypted = (0, crypto_1.aesDecryptGCM)(encPayload, decKey, encIv, aad);
|
|
120
|
+
return WAProto_1.proto.Message.PollVoteMessage.decode(decrypted);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
// Silenciar errores de desencriptación de polls - no son críticos
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
114
126
|
function toBinary(txt) {
|
|
115
127
|
return Buffer.from(txt);
|
|
116
128
|
}
|
|
@@ -367,6 +379,8 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
367
379
|
const pollCreatorJid = (0, generics_1.getKeyAuthor)(creationMsgKey, meIdNormalised);
|
|
368
380
|
const voterJid = (0, generics_1.getKeyAuthor)(message.key, meIdNormalised);
|
|
369
381
|
const pollEncKey = (_s = pollMsg.messageContextInfo) === null || _s === void 0 ? void 0 : _s.messageSecret;
|
|
382
|
+
|
|
383
|
+
// 🔧 REPARADO: Manejo seguro de decryptPollVote
|
|
370
384
|
try {
|
|
371
385
|
const voteMsg = decryptPollVote(content.pollUpdateMessage.vote, {
|
|
372
386
|
pollEncKey,
|
|
@@ -374,20 +388,24 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
374
388
|
pollMsgId: creationMsgKey.id,
|
|
375
389
|
voterJid,
|
|
376
390
|
});
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
391
|
+
|
|
392
|
+
// Solo emitir si se desencriptó correctamente
|
|
393
|
+
if (voteMsg) {
|
|
394
|
+
ev.emit('messages.update', [
|
|
395
|
+
{
|
|
396
|
+
key: creationMsgKey,
|
|
397
|
+
update: {
|
|
398
|
+
pollUpdates: [
|
|
399
|
+
{
|
|
400
|
+
pollUpdateMessageKey: message.key,
|
|
401
|
+
vote: voteMsg,
|
|
402
|
+
senderTimestampMs: content.pollUpdateMessage.senderTimestampMs.toNumber(),
|
|
403
|
+
}
|
|
404
|
+
]
|
|
405
|
+
}
|
|
388
406
|
}
|
|
389
|
-
|
|
390
|
-
|
|
407
|
+
]);
|
|
408
|
+
}
|
|
391
409
|
}
|
|
392
410
|
catch (err) {
|
|
393
411
|
logger === null || logger === void 0 ? void 0 : logger.warn({ err, creationMsgKey }, 'failed to decrypt poll vote');
|