@systemzero/baileys 1.0.4 → 1.0.6
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 +595 -762
- package/lib/Defaults/index.js +9 -3
- package/lib/MB.cjs +8 -0
- package/lib/MessageBuilder.cjs +2509 -0
- package/lib/Socket/chats.js +12 -1
- package/lib/Socket/groups.js +13 -4
- package/lib/Socket/messages-recv.js +36 -2
- package/lib/Socket/messages-recv.js.bak +1273 -0
- package/lib/Socket/messages-send.js +2 -1
- package/lib/Types/Message.js +7 -0
- package/lib/Utils/bad-mac-handler.js +158 -0
- package/lib/Utils/get-best-version.js +41 -0
- package/lib/Utils/get-name.d.ts +1 -0
- package/lib/Utils/get-name.js +54 -0
- package/lib/Utils/group-status-detection.js +113 -0
- package/lib/Utils/index.js +7 -0
- package/lib/Utils/logger.js +4 -1
- package/lib/Utils/messages-media.js +42 -3
- package/lib/Utils/messages.js +641 -10
- package/lib/Utils/payment-detection.js +212 -0
- package/lib/Utils/payment-guard.d.ts +15 -0
- package/lib/Utils/payment-guard.js +142 -0
- package/lib/Utils/resolve-lid-phone.js +30 -0
- package/lib/WABinary/jid-utils.js +245 -1
- package/package.json +4 -3
- package/lib/Defaults/index.d.ts.map +0 -1
- package/lib/Defaults/index.js.map +0 -1
- package/lib/Signal/Group/ciphertext-message.d.ts.map +0 -1
- package/lib/Signal/Group/ciphertext-message.js.map +0 -1
- package/lib/Signal/Group/group-session-builder.d.ts.map +0 -1
- package/lib/Signal/Group/group-session-builder.js.map +0 -1
- package/lib/Signal/Group/group_cipher.d.ts.map +0 -1
- package/lib/Signal/Group/group_cipher.js.map +0 -1
- package/lib/Signal/Group/index.d.ts.map +0 -1
- package/lib/Signal/Group/index.js.map +0 -1
- package/lib/Signal/Group/keyhelper.d.ts.map +0 -1
- package/lib/Signal/Group/keyhelper.js.map +0 -1
- package/lib/Signal/Group/sender-chain-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-chain-key.js.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-name.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-name.js.map +0 -1
- package/lib/Signal/Group/sender-key-record.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-record.js.map +0 -1
- package/lib/Signal/Group/sender-key-state.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-state.js.map +0 -1
- package/lib/Signal/Group/sender-message-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-message-key.js.map +0 -1
- package/lib/Signal/libsignal.d.ts.map +0 -1
- package/lib/Signal/libsignal.js.map +0 -1
- package/lib/Signal/lid-mapping.d.ts.map +0 -1
- package/lib/Signal/lid-mapping.js.map +0 -1
- package/lib/Socket/Client/index.d.ts.map +0 -1
- package/lib/Socket/Client/index.js.map +0 -1
- package/lib/Socket/Client/types.d.ts.map +0 -1
- package/lib/Socket/Client/types.js.map +0 -1
- package/lib/Socket/Client/websocket.d.ts.map +0 -1
- package/lib/Socket/Client/websocket.js.map +0 -1
- package/lib/Socket/business.d.ts.map +0 -1
- package/lib/Socket/business.js.map +0 -1
- package/lib/Socket/chats.d.ts.map +0 -1
- package/lib/Socket/chats.js.map +0 -1
- package/lib/Socket/communities.d.ts.map +0 -1
- package/lib/Socket/communities.js.map +0 -1
- package/lib/Socket/groups.d.ts.map +0 -1
- package/lib/Socket/groups.js.map +0 -1
- package/lib/Socket/index.d.ts.map +0 -1
- package/lib/Socket/index.js.map +0 -1
- package/lib/Socket/messages-recv.d.ts.map +0 -1
- package/lib/Socket/messages-recv.js.map +0 -1
- package/lib/Socket/messages-send.d.ts.map +0 -1
- package/lib/Socket/messages-send.js.map +0 -1
- package/lib/Socket/mex.d.ts.map +0 -1
- package/lib/Socket/mex.js.map +0 -1
- package/lib/Socket/newsletter.d.ts.map +0 -1
- package/lib/Socket/newsletter.js.map +0 -1
- package/lib/Socket/socket.d.ts.map +0 -1
- package/lib/Socket/socket.js.map +0 -1
- package/lib/Types/Auth.d.ts.map +0 -1
- package/lib/Types/Auth.js.map +0 -1
- package/lib/Types/Bussines.d.ts.map +0 -1
- package/lib/Types/Bussines.js.map +0 -1
- package/lib/Types/Call.d.ts.map +0 -1
- package/lib/Types/Call.js.map +0 -1
- package/lib/Types/Chat.d.ts.map +0 -1
- package/lib/Types/Chat.js.map +0 -1
- package/lib/Types/Contact.d.ts.map +0 -1
- package/lib/Types/Contact.js.map +0 -1
- package/lib/Types/Events.d.ts.map +0 -1
- package/lib/Types/Events.js.map +0 -1
- package/lib/Types/GroupMetadata.d.ts.map +0 -1
- package/lib/Types/GroupMetadata.js.map +0 -1
- package/lib/Types/Label.d.ts.map +0 -1
- package/lib/Types/Label.js.map +0 -1
- package/lib/Types/LabelAssociation.d.ts.map +0 -1
- package/lib/Types/LabelAssociation.js.map +0 -1
- package/lib/Types/Message.d.ts.map +0 -1
- package/lib/Types/Message.js.map +0 -1
- package/lib/Types/Newsletter.d.ts.map +0 -1
- package/lib/Types/Newsletter.js.map +0 -1
- package/lib/Types/Product.d.ts.map +0 -1
- package/lib/Types/Product.js.map +0 -1
- package/lib/Types/Signal.d.ts.map +0 -1
- package/lib/Types/Signal.js.map +0 -1
- package/lib/Types/Socket.d.ts.map +0 -1
- package/lib/Types/Socket.js.map +0 -1
- package/lib/Types/State.d.ts.map +0 -1
- package/lib/Types/State.js.map +0 -1
- package/lib/Types/USync.d.ts.map +0 -1
- package/lib/Types/USync.js.map +0 -1
- package/lib/Types/index.d.ts.map +0 -1
- package/lib/Types/index.js.map +0 -1
- package/lib/Utils/auth-utils.d.ts.map +0 -1
- package/lib/Utils/auth-utils.js.map +0 -1
- package/lib/Utils/browser-utils.d.ts.map +0 -1
- package/lib/Utils/browser-utils.js.map +0 -1
- package/lib/Utils/business.d.ts.map +0 -1
- package/lib/Utils/business.js.map +0 -1
- package/lib/Utils/chat-utils.d.ts.map +0 -1
- package/lib/Utils/chat-utils.js.map +0 -1
- package/lib/Utils/crypto.d.ts.map +0 -1
- package/lib/Utils/crypto.js.map +0 -1
- package/lib/Utils/decode-wa-message.d.ts.map +0 -1
- package/lib/Utils/decode-wa-message.js.map +0 -1
- package/lib/Utils/event-buffer.d.ts.map +0 -1
- package/lib/Utils/event-buffer.js.map +0 -1
- package/lib/Utils/generics.d.ts.map +0 -1
- package/lib/Utils/generics.js.map +0 -1
- package/lib/Utils/history.d.ts.map +0 -1
- package/lib/Utils/history.js.map +0 -1
- package/lib/Utils/index.d.ts.map +0 -1
- package/lib/Utils/index.js.map +0 -1
- package/lib/Utils/link-preview.d.ts.map +0 -1
- package/lib/Utils/link-preview.js.map +0 -1
- package/lib/Utils/logger.d.ts.map +0 -1
- package/lib/Utils/logger.js.map +0 -1
- package/lib/Utils/lt-hash.d.ts.map +0 -1
- package/lib/Utils/lt-hash.js.map +0 -1
- package/lib/Utils/make-mutex.d.ts.map +0 -1
- package/lib/Utils/make-mutex.js.map +0 -1
- package/lib/Utils/message-retry-manager.d.ts.map +0 -1
- package/lib/Utils/message-retry-manager.js.map +0 -1
- package/lib/Utils/messages-media.d.ts.map +0 -1
- package/lib/Utils/messages-media.js.map +0 -1
- package/lib/Utils/messages.d.ts.map +0 -1
- package/lib/Utils/messages.js.map +0 -1
- package/lib/Utils/noise-handler.d.ts.map +0 -1
- package/lib/Utils/noise-handler.js.map +0 -1
- package/lib/Utils/pre-key-manager.d.ts.map +0 -1
- package/lib/Utils/pre-key-manager.js.map +0 -1
- package/lib/Utils/process-message.d.ts.map +0 -1
- package/lib/Utils/process-message.js.map +0 -1
- package/lib/Utils/signal.d.ts.map +0 -1
- package/lib/Utils/signal.js.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.js.map +0 -1
- package/lib/Utils/validate-connection.d.ts.map +0 -1
- package/lib/Utils/validate-connection.js.map +0 -1
- package/lib/WABinary/constants.d.ts.map +0 -1
- package/lib/WABinary/constants.js.map +0 -1
- package/lib/WABinary/decode.d.ts.map +0 -1
- package/lib/WABinary/decode.js.map +0 -1
- package/lib/WABinary/encode.d.ts.map +0 -1
- package/lib/WABinary/encode.js.map +0 -1
- package/lib/WABinary/generic-utils.d.ts.map +0 -1
- package/lib/WABinary/generic-utils.js.map +0 -1
- package/lib/WABinary/index.d.ts.map +0 -1
- package/lib/WABinary/index.js.map +0 -1
- package/lib/WABinary/jid-utils.d.ts.map +0 -1
- package/lib/WABinary/jid-utils.js.map +0 -1
- package/lib/WABinary/types.d.ts.map +0 -1
- package/lib/WABinary/types.js.map +0 -1
- package/lib/WAM/BinaryInfo.d.ts.map +0 -1
- package/lib/WAM/BinaryInfo.js.map +0 -1
- package/lib/WAM/constants.d.ts.map +0 -1
- package/lib/WAM/constants.js.map +0 -1
- package/lib/WAM/encode.d.ts.map +0 -1
- package/lib/WAM/encode.js.map +0 -1
- package/lib/WAM/index.d.ts.map +0 -1
- package/lib/WAM/index.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/index.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/index.js.map +0 -1
- package/lib/WAUSync/USyncQuery.d.ts.map +0 -1
- package/lib/WAUSync/USyncQuery.js.map +0 -1
- package/lib/WAUSync/USyncUser.d.ts.map +0 -1
- package/lib/WAUSync/USyncUser.js.map +0 -1
- package/lib/WAUSync/index.d.ts.map +0 -1
- package/lib/WAUSync/index.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
|
@@ -568,7 +568,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
568
568
|
if (isNewsletter) {
|
|
569
569
|
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
570
570
|
const bytes = encodeNewsletterMessage(patched);
|
|
571
|
-
binaryNodeContent.push({ tag: 'plaintext', attrs:
|
|
571
|
+
binaryNodeContent.push({ tag: 'plaintext', attrs: extraAttrs, content: bytes });
|
|
572
572
|
const stanza = {
|
|
573
573
|
tag: 'message',
|
|
574
574
|
attrs: { to: jid, id: msgId, type: getMessageType(message), ...(additionalAttributes || {}) },
|
|
@@ -782,6 +782,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
782
782
|
else if (message.contactsArrayMessage) return 'contact_array';
|
|
783
783
|
else if (message.liveLocationMessage) return 'livelocation';
|
|
784
784
|
else if (message.stickerMessage) return 'sticker';
|
|
785
|
+
else if (message.lottieStickerMessage) return 'sticker';
|
|
785
786
|
else if (message.listMessage) return 'list';
|
|
786
787
|
else if (message.listResponseMessage) return 'list_response';
|
|
787
788
|
else if (message.buttonsResponseMessage) return 'buttons_response';
|
package/lib/Types/Message.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { proto } from '../../WAProto/index.js';
|
|
2
|
+
export const ButtonHeaderType = proto.Message.ButtonsMessage.HeaderType;
|
|
3
|
+
export const ButtonType = proto.Message.ButtonsMessage.Button.Type;
|
|
4
|
+
export const CarouselCardType = proto.Message.InteractiveMessage.CarouselMessage.CarouselCardType;
|
|
5
|
+
export const ListType = proto.Message.ListMessage.ListType;
|
|
6
|
+
export const ProtocolType = proto.Message.ProtocolMessage.Type;
|
|
7
|
+
export const AssociationType = proto.MessageAssociation?.AssociationType;
|
|
8
|
+
|
|
2
9
|
// export the WAMessage Prototypes
|
|
3
10
|
export { proto as WAProto };
|
|
4
11
|
export const WAMessageStubType = proto.WebMessageInfo.StubType;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilitário para lidar com erros "Bad MAC", comuns em bots WhatsApp usando
|
|
3
|
+
* Baileys quando a sessão Signal de um par fica desincronizada (ex: o
|
|
4
|
+
* outro lado reinstalou o WhatsApp, trocou de aparelho, ou houve perda de
|
|
5
|
+
* mensagens na troca de chaves). Não é uma falha do bot — é esperado que
|
|
6
|
+
* aconteça ocasionalmente em qualquer cliente Signal Protocol.
|
|
7
|
+
*
|
|
8
|
+
* Este módulo fornece funções para detectar, contar e lidar graciosamente
|
|
9
|
+
* com esses erros, sem derrubar o processo do bot.
|
|
10
|
+
*
|
|
11
|
+
* @author Dev Gui (original), integrado na lib para System Zero. By Josué </>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { errorLog, warningLog } from './logger.js';
|
|
17
|
+
|
|
18
|
+
export class BadMacHandler {
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.errorCount = 0;
|
|
21
|
+
this.maxRetries = options.maxRetries ?? 5;
|
|
22
|
+
this.resetInterval = options.resetInterval ?? 300000; // 5 min
|
|
23
|
+
this.lastReset = Date.now();
|
|
24
|
+
// pasta de auth configurável — por padrão segue o padrão Baileys comum
|
|
25
|
+
this.authFolder = options.authFolder ?? path.resolve(process.cwd(), 'assets', 'auth', 'baileys');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
isBadMacError(error) {
|
|
29
|
+
const errorMessage = error?.message || error?.toString() || '';
|
|
30
|
+
return (
|
|
31
|
+
errorMessage.includes('Bad MAC') ||
|
|
32
|
+
errorMessage.includes('MAC verification failed') ||
|
|
33
|
+
errorMessage.includes('decryption failed')
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
isSessionError(error) {
|
|
38
|
+
const errorMessage = error?.message || error?.toString() || '';
|
|
39
|
+
return (
|
|
40
|
+
errorMessage.includes('Session') ||
|
|
41
|
+
errorMessage.includes('signal protocol') ||
|
|
42
|
+
errorMessage.includes('decrypt') ||
|
|
43
|
+
this.isBadMacError(error)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Remove arquivos de sessão Signal problemáticos, preservando SEMPRE as
|
|
49
|
+
* credenciais principais (creds.json, app-state-sync-key/version) — só
|
|
50
|
+
* descarta arquivos de sessão por par (que serão renegociados
|
|
51
|
+
* automaticamente na próxima troca de chaves).
|
|
52
|
+
*/
|
|
53
|
+
clearProblematicSessionFiles() {
|
|
54
|
+
try {
|
|
55
|
+
if (!fs.existsSync(this.authFolder)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const PRESERVE_PATTERNS = ['app-state-sync-key', 'creds.json', 'app-state-sync-version'];
|
|
60
|
+
const files = fs.readdirSync(this.authFolder);
|
|
61
|
+
let removedCount = 0;
|
|
62
|
+
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
const filePath = path.join(this.authFolder, file);
|
|
65
|
+
if (!fs.statSync(filePath).isFile()) continue;
|
|
66
|
+
|
|
67
|
+
const mustPreserve = PRESERVE_PATTERNS.some((pattern) => file.includes(pattern));
|
|
68
|
+
if (mustPreserve) continue;
|
|
69
|
+
|
|
70
|
+
// só remove arquivos de sessão por par (ex: session-*.json)
|
|
71
|
+
if (file.startsWith('session-') || file.includes('sender-key')) {
|
|
72
|
+
fs.unlinkSync(filePath);
|
|
73
|
+
removedCount++;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (removedCount > 0) {
|
|
78
|
+
warningLog(`${removedCount} arquivo(s) de sessão problemáticos removidos. Credenciais principais preservadas.`);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return false;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
errorLog(`Erro ao limpar arquivos de sessão: ${error.message}`);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
incrementErrorCount() {
|
|
90
|
+
this.errorCount++;
|
|
91
|
+
errorLog(`Bad MAC error count: ${this.errorCount}/${this.maxRetries}`);
|
|
92
|
+
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
if (now - this.lastReset > this.resetInterval) {
|
|
95
|
+
this.resetErrorCount();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
resetErrorCount() {
|
|
100
|
+
const previousCount = this.errorCount;
|
|
101
|
+
this.errorCount = 0;
|
|
102
|
+
this.lastReset = Date.now();
|
|
103
|
+
|
|
104
|
+
if (previousCount > 0) {
|
|
105
|
+
warningLog(`Reset do contador de Bad MAC errors. Contador anterior: ${previousCount}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
hasReachedLimit() {
|
|
110
|
+
return this.errorCount >= this.maxRetries;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @returns {boolean} true se o erro foi tratado (Bad MAC engolido),
|
|
115
|
+
* false se NÃO era Bad MAC (deve ser relançado pelo caller)
|
|
116
|
+
*/
|
|
117
|
+
handleError(error, context = 'unknown') {
|
|
118
|
+
if (!this.isBadMacError(error)) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
errorLog(`Bad MAC error detectado em ${context}: ${error.message}`);
|
|
123
|
+
this.incrementErrorCount();
|
|
124
|
+
|
|
125
|
+
if (this.hasReachedLimit()) {
|
|
126
|
+
warningLog(`Limite de Bad MAC errors atingido (${this.maxRetries}). Considere reiniciar o bot ou limpar sessões com clearProblematicSessionFiles().`);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
warningLog(`Ignorando Bad MAC error e continuando operação... (${this.errorCount}/${this.maxRetries})`);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Envolve uma função async — engole Bad MAC, relança qualquer outro erro. */
|
|
135
|
+
createSafeWrapper(fn, context) {
|
|
136
|
+
return async (...args) => {
|
|
137
|
+
try {
|
|
138
|
+
return await fn(...args);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (this.handleError(error, context)) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
getStats() {
|
|
149
|
+
return {
|
|
150
|
+
errorCount: this.errorCount,
|
|
151
|
+
maxRetries: this.maxRetries,
|
|
152
|
+
lastReset: new Date(this.lastReset).toISOString(),
|
|
153
|
+
timeUntilReset: Math.max(0, this.resetInterval - (Date.now() - this.lastReset)),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export const badMacHandler = new BadMacHandler();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// lib/Utils/get-best-version.js
|
|
2
|
+
//
|
|
3
|
+
// fetchLatestWaWebVersion() e fetchLatestBaileysVersion() SEMPRE retornam um
|
|
4
|
+
// objeto com `version` preenchido, mesmo quando a busca falha — nesse caso
|
|
5
|
+
// devolvem isLatest:false e um valor antigo fixo embutido na lib. Checar só
|
|
6
|
+
// `if (result.version)` nunca detecta a falha, porque version sempre existe.
|
|
7
|
+
//
|
|
8
|
+
// Este helper tenta as duas fontes, na ordem, e só aceita um resultado se
|
|
9
|
+
// `isLatest === true` (ou seja, se realmente buscou fresco da rede). Só cai
|
|
10
|
+
// no valor fixo antigo se AMBAS as fontes falharem de verdade.
|
|
11
|
+
|
|
12
|
+
import { fetchLatestWaWebVersion } from './generics.js';
|
|
13
|
+
import { fetchLatestBaileysVersion } from './generics.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {object} [options] - passado direto pras duas funções de fetch
|
|
17
|
+
* @returns {Promise<{ version: number[], isLatest: boolean, source: string }>}
|
|
18
|
+
*/
|
|
19
|
+
export const getBestWaVersion = async (options = {}) => {
|
|
20
|
+
try {
|
|
21
|
+
const web = await fetchLatestWaWebVersion(options);
|
|
22
|
+
if (web?.isLatest && web?.version) {
|
|
23
|
+
return { version: web.version, isLatest: true, source: 'web.whatsapp.com' };
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// segue pra próxima fonte
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const github = await fetchLatestBaileysVersion(options);
|
|
31
|
+
if (github?.isLatest && github?.version) {
|
|
32
|
+
return { version: github.version, isLatest: true, source: 'github' };
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
// segue pro fallback fixo
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// as duas fontes falharam de verdade — usa o valor fixo embutido,
|
|
39
|
+
// mas avisa explicitamente que NÃO é a versão mais atual
|
|
40
|
+
return { version: [2, 3000, 1027934701], isLatest: false, source: 'fallback-fixo' };
|
|
41
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getName: (msg: any, contactStore?: Record<string, { name?: string; notify?: string; verifiedName?: string }>) => string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// lib/Utils/get-name.js
|
|
2
|
+
// Resolve o nome do remetente com cobertura total (nunca retorna vazio).
|
|
3
|
+
// Ordem de prioridade:
|
|
4
|
+
// 1) Nome salvo localmente (store/contatos) — mais confiável
|
|
5
|
+
// 2) verifiedName (conta business confirmada pela Meta)
|
|
6
|
+
// 3) notify / pushName da própria mensagem
|
|
7
|
+
// 4) Nome resolvido via cache LID -> JID (se sender for @lid)
|
|
8
|
+
// 5) Número de telefone formatado (fallback final, nunca undefined)
|
|
9
|
+
|
|
10
|
+
import { jidDecode, isLidUser, sharedLidPhoneCache, lidToJid } from '../WABinary/jid-utils.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {object} msg - mensagem completa do Baileys (proto.IWebMessageInfo)
|
|
14
|
+
* @param {object} [contactStore] - opcional: { [jid]: { name, notify, verifiedName } }
|
|
15
|
+
* @returns {string} nome final, garantido não-vazio
|
|
16
|
+
*/
|
|
17
|
+
export const getName = (msg, contactStore) => {
|
|
18
|
+
try {
|
|
19
|
+
const key = msg?.key || {};
|
|
20
|
+
let sender = key.participant || key.remoteJid || '';
|
|
21
|
+
|
|
22
|
+
// se vier @lid, tenta resolver pro JID real (telefone) primeiro,
|
|
23
|
+
// pois o contactStore normalmente é indexado por @s.whatsapp.net
|
|
24
|
+
let resolvedSender = sender;
|
|
25
|
+
if (isLidUser(sender)) {
|
|
26
|
+
const phone = sharedLidPhoneCache.getPhoneForLid(sender) || lidToJid(sender);
|
|
27
|
+
if (phone && phone !== sender) resolvedSender = phone;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 1) contato salvo localmente
|
|
31
|
+
const contact = contactStore?.[resolvedSender] || contactStore?.[sender];
|
|
32
|
+
if (contact?.name && contact.name.trim()) return contact.name.trim();
|
|
33
|
+
|
|
34
|
+
// 2) verifiedName (conta business)
|
|
35
|
+
if (contact?.verifiedName && contact.verifiedName.trim()) return contact.verifiedName.trim();
|
|
36
|
+
|
|
37
|
+
// 3) pushName / notify da mensagem em si
|
|
38
|
+
const pushName = msg?.pushName || contact?.notify;
|
|
39
|
+
if (pushName && pushName.trim() && pushName.trim() !== 'WhatsApp User') {
|
|
40
|
+
return pushName.trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 4) fallback: número de telefone formatado a partir do JID resolvido
|
|
44
|
+
const decoded = jidDecode(resolvedSender);
|
|
45
|
+
if (decoded?.user) {
|
|
46
|
+
return `+${decoded.user}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 5) último recurso absoluto — nunca undefined/empty
|
|
50
|
+
return 'Usuário desconhecido';
|
|
51
|
+
} catch {
|
|
52
|
+
return 'Usuário desconhecido';
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detecção robusta de mensagens de status-em-grupo (marcação de status no grupo).
|
|
3
|
+
*
|
|
4
|
+
* Cobre:
|
|
5
|
+
* - groupStatusMentionMessage / groupStatusMessage / groupStatusMessageV2
|
|
6
|
+
* - isGroupStatus: true | 1 em qualquer nível
|
|
7
|
+
* - statusAttributions com type GROUP_STATUS / type 5 / groupStatus: true
|
|
8
|
+
* - mensagens aninhadas em wrappers (ephemeral, viewOnce, etc)
|
|
9
|
+
*
|
|
10
|
+
* @author Dev Gui (original), integrado na lib para System Zero. By Josué </>
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const MAX_MESSAGE_UNWRAP_DEPTH = 5;
|
|
14
|
+
const MAX_FLAG_SCAN_DEPTH = 8;
|
|
15
|
+
|
|
16
|
+
const STRONG_GROUP_STATUS_MESSAGE_KEYS = new Set([
|
|
17
|
+
'groupStatusMentionMessage',
|
|
18
|
+
'groupStatusMessage',
|
|
19
|
+
'groupStatusMessageV2',
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const WRAPPED_MESSAGE_KEYS = [
|
|
23
|
+
'ephemeralMessage',
|
|
24
|
+
'viewOnceMessage',
|
|
25
|
+
'viewOnceMessageV2',
|
|
26
|
+
'viewOnceMessageV2Extension',
|
|
27
|
+
'documentWithCaptionMessage',
|
|
28
|
+
'statusMentionMessage',
|
|
29
|
+
'groupStatusMentionMessage',
|
|
30
|
+
'groupStatusMessage',
|
|
31
|
+
'groupStatusMessageV2',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
export function isGroupStatusValue(value) {
|
|
35
|
+
return value === true || value === 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function canScanObject(value) {
|
|
39
|
+
return value && typeof value === 'object' && !(value instanceof ArrayBuffer) && !ArrayBuffer.isView(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function hasGroupStatusAttribution(statusAttributions) {
|
|
43
|
+
if (!Array.isArray(statusAttributions)) return false;
|
|
44
|
+
|
|
45
|
+
return statusAttributions.some(
|
|
46
|
+
(sa) =>
|
|
47
|
+
canScanObject(sa) &&
|
|
48
|
+
(Boolean(sa.groupStatus) || sa.attributionData === 'groupStatus' || sa.type === 'GROUP_STATUS' || sa.type === 5)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function hasGroupStatusContextInfo(contextInfo) {
|
|
53
|
+
return (
|
|
54
|
+
canScanObject(contextInfo) &&
|
|
55
|
+
(isGroupStatusValue(contextInfo.isGroupStatus) || hasGroupStatusAttribution(contextInfo.statusAttributions))
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function hasGroupStatusFlag(value, depth = 0, seenObjects = new WeakSet()) {
|
|
60
|
+
if (!canScanObject(value) || depth > MAX_FLAG_SCAN_DEPTH || seenObjects.has(value)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
seenObjects.add(value);
|
|
65
|
+
|
|
66
|
+
for (const [key, childValue] of Object.entries(value)) {
|
|
67
|
+
if (key === 'quotedMessage') continue;
|
|
68
|
+
|
|
69
|
+
if (STRONG_GROUP_STATUS_MESSAGE_KEYS.has(key) && canScanObject(childValue)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (key === 'isGroupStatus' && isGroupStatusValue(childValue)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (key === 'statusAttributions' && hasGroupStatusAttribution(childValue)) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (key === 'contextInfo' && hasGroupStatusContextInfo(childValue)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (hasGroupStatusFlag(childValue, depth + 1, seenObjects)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getCurrentMessageContentVariants(message, depth = 0, seenObjects = new WeakSet()) {
|
|
94
|
+
if (!canScanObject(message) || depth > MAX_MESSAGE_UNWRAP_DEPTH || seenObjects.has(message)) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
seenObjects.add(message);
|
|
99
|
+
|
|
100
|
+
const variants = [message];
|
|
101
|
+
|
|
102
|
+
for (const key of WRAPPED_MESSAGE_KEYS) {
|
|
103
|
+
const wrappedMessage = message[key]?.message;
|
|
104
|
+
variants.push(...getCurrentMessageContentVariants(wrappedMessage, depth + 1, seenObjects));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return variants;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Verifica se a webMessage é uma marcação de status em grupo, inclusive em wrappers ou níveis profundos. */
|
|
111
|
+
export function hasGroupStatusMessage(webMessage) {
|
|
112
|
+
return getCurrentMessageContentVariants(webMessage?.message).some((message) => hasGroupStatusFlag(message));
|
|
113
|
+
}
|
package/lib/Utils/index.js
CHANGED
|
@@ -16,4 +16,11 @@ export * from './event-buffer.js';
|
|
|
16
16
|
export * from './process-message.js';
|
|
17
17
|
export * from './message-retry-manager.js';
|
|
18
18
|
export * from './browser-utils.js';
|
|
19
|
+
export * from './get-name.js';
|
|
20
|
+
export * from './payment-guard.js';
|
|
21
|
+
export * from './payment-detection.js';
|
|
22
|
+
export * from './group-status-detection.js';
|
|
23
|
+
export * from './bad-mac-handler.js';
|
|
24
|
+
export * from './resolve-lid-phone.js';
|
|
25
|
+
export * from './get-best-version.js';
|
|
19
26
|
//# sourceMappingURL=index.js.map
|
package/lib/Utils/logger.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import P from 'pino';
|
|
2
|
-
|
|
2
|
+
const logger = P({ timestamp: () => `,"time":"${new Date().toJSON()}"` });
|
|
3
|
+
export const errorLog = (msg) => logger.error(msg);
|
|
4
|
+
export const warningLog = (msg) => logger.warn(msg);
|
|
5
|
+
export default logger;
|
|
3
6
|
//# sourceMappingURL=logger.js.map
|
|
@@ -7,13 +7,51 @@ import { tmpdir } from 'os';
|
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { Readable, Transform } from 'stream';
|
|
9
9
|
import { URL } from 'url';
|
|
10
|
+
import { promisify } from 'util';
|
|
10
11
|
import { proto } from '../../WAProto/index.js';
|
|
11
12
|
import { DEFAULT_ORIGIN, MEDIA_HKDF_KEY_MAPPING, MEDIA_PATH_MAP } from '../Defaults/index.js';
|
|
12
13
|
import { getBinaryNodeChild, getBinaryNodeChildBuffer, jidNormalizedUser } from '../WABinary/index.js';
|
|
13
14
|
import { aesDecryptGCM, aesEncryptGCM, hkdf } from './crypto.js';
|
|
14
15
|
import { generateMessageIDV2 } from './generics.js';
|
|
15
16
|
const getTmpFilesDirectory = () => tmpdir();
|
|
16
|
-
const
|
|
17
|
+
const execAsync = promisify(exec);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Converte QUALQUER áudio de entrada pra opus/ogg mono 16kHz — o formato
|
|
21
|
+
* exato que o player de PTT do WhatsApp espera. Sem isso, marcar `ptt: true`
|
|
22
|
+
* num mp3/m4a só troca o RÓTULO do mimetype sem mudar os bytes reais, e o
|
|
23
|
+
* WhatsApp mostra "algo errado com o arquivo de áudio" ao tentar decodificar.
|
|
24
|
+
*
|
|
25
|
+
* @param {string | Buffer} input - caminho de arquivo local, URL http(s), ou Buffer já em memória
|
|
26
|
+
* @returns {Promise<string>} caminho do arquivo .ogg convertido (temporário — chame fs.unlink depois de usar)
|
|
27
|
+
*/
|
|
28
|
+
export async function transcodeAudioToOpus(input) {
|
|
29
|
+
const outputPath = join(getTmpFilesDirectory(), 'ptt-' + generateMessageIDV2() + '.ogg');
|
|
30
|
+
let inputPath = input;
|
|
31
|
+
let tempInputPath;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (Buffer.isBuffer(input)) {
|
|
35
|
+
tempInputPath = join(getTmpFilesDirectory(), 'ptt-src-' + generateMessageIDV2());
|
|
36
|
+
await fs.writeFile(tempInputPath, input);
|
|
37
|
+
inputPath = tempInputPath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// -vn: ignora qualquer vídeo/capa embutida (mp3 com artwork, por exemplo)
|
|
41
|
+
// -ac 1 -ar 16000: mono 16kHz — espec exata do PTT nativo do WhatsApp
|
|
42
|
+
// -c:a libopus -b:a 32k: codec real opus, não só o rótulo
|
|
43
|
+
const cmd = `ffmpeg -i "${inputPath}" -y -vn -ac 1 -ar 16000 -c:a libopus -b:a 32k -f ogg "${outputPath}"`;
|
|
44
|
+
await execAsync(cmd);
|
|
45
|
+
|
|
46
|
+
return outputPath;
|
|
47
|
+
} finally {
|
|
48
|
+
if (tempInputPath) {
|
|
49
|
+
await fs.unlink(tempInputPath).catch(() => {});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const getImageProcessingLibrary = async () => {
|
|
17
55
|
//@ts-ignore
|
|
18
56
|
const [jimp, sharp] = await Promise.all([import('jimp').catch(() => { }), import('sharp').catch(() => { })]);
|
|
19
57
|
if (sharp) {
|
|
@@ -210,7 +248,8 @@ export async function getAudioWaveform(buffer, logger) {
|
|
|
210
248
|
}
|
|
211
249
|
const audioBuffer = await decoder(audioData);
|
|
212
250
|
const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
|
|
213
|
-
const samples = 64;
|
|
251
|
+
const samples = 64;
|
|
252
|
+
const minHeight = 0.05;
|
|
214
253
|
const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
|
|
215
254
|
const filteredData = [];
|
|
216
255
|
for (let i = 0; i < samples; i++) {
|
|
@@ -225,7 +264,7 @@ export async function getAudioWaveform(buffer, logger) {
|
|
|
225
264
|
const multiplier = Math.pow(Math.max(...filteredData), -1);
|
|
226
265
|
const normalizedData = filteredData.map(n => n * multiplier);
|
|
227
266
|
// Generate waveform like WhatsApp
|
|
228
|
-
const waveform = new Uint8Array(normalizedData.map(n => Math.floor(100 * n)));
|
|
267
|
+
const waveform = new Uint8Array(normalizedData.map(n => Math.max(minHeight, n)).map(n => Math.floor(100 * n)));
|
|
229
268
|
return waveform;
|
|
230
269
|
}
|
|
231
270
|
catch (e) {
|