@kaikybrofc/omnizap-system 2.2.2 → 2.2.4

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/.env.example CHANGED
@@ -427,6 +427,14 @@ STICKER_DATA_LIST_LIMIT=50
427
427
  STICKER_DATA_LIST_MAX_LIMIT=200
428
428
  STICKER_DATA_SCAN_MAX_FILES=10000
429
429
 
430
+ # Login web via WhatsApp -> Google
431
+ WHATSAPP_LOGIN_TRIGGER=iniciar
432
+ WHATSAPP_LOGIN_BASE_URL=https://omnizap.shop
433
+ WHATSAPP_LOGIN_PATH=/login/
434
+ WHATSAPP_LOGIN_LINK_SECRET=troque_por_um_segredo_forte
435
+ WHATSAPP_LOGIN_LINK_TTL_SECONDS=900
436
+ WHATSAPP_LOGIN_REQUIRE_SIGNATURE=true
437
+
430
438
  # Paths locais (legado/uso auxiliar)
431
439
  STORE_PATH=./temp
432
440
 
package/README.md CHANGED
@@ -33,6 +33,12 @@ Use as rotas abaixo para consumir o bloco já renderizado com dados do sistema:
33
33
  - JSON: `GET /api/sticker-packs/readme-summary`
34
34
  - Markdown: `GET /api/sticker-packs/readme-markdown`
35
35
 
36
+ Para atualizar este `README.md` automaticamente com o conteúdo renderizado:
37
+
38
+ ```bash
39
+ npm run readme:sync-snapshot
40
+ ```
41
+
36
42
  Conteúdo incluído no snapshot:
37
43
 
38
44
  - total de usuários (`lid_map`)
@@ -44,6 +50,38 @@ Conteúdo incluído no snapshot:
44
50
 
45
51
  Atualização em cache: **30 minutos** por padrão (`README_SUMMARY_CACHE_SECONDS=1800`).
46
52
 
53
+ <!-- README_SNAPSHOT:START -->
54
+ ### Snapshot do Sistema
55
+
56
+ > Atualizado em `2026-02-28T01:18:30.283Z` | cache `1800s`
57
+
58
+ | Métrica | Valor |
59
+ | --- | ---: |
60
+ | Usuários (lid_map) | 5.502 |
61
+ | Grupos | 116 |
62
+ | Packs | 295 |
63
+ | Stickers | 6.314 |
64
+ | Mensagens registradas | 438.975 |
65
+
66
+ #### Tipos de mensagem mais usados (amostra: 25.000)
67
+ | Tipo | Total |
68
+ | --- | ---: |
69
+ | `texto` | 16.526 |
70
+ | `figurinha` | 4.263 |
71
+ | `reacao` | 1.619 |
72
+ | `imagem` | 1.326 |
73
+ | `outros` | 800 |
74
+ | `video` | 245 |
75
+ | `audio` | 215 |
76
+ | `documento` | 6 |
77
+
78
+ <details><summary>Comandos disponíveis (62)</summary>
79
+
80
+ `/add` · `/addmode` · `/autorequests` · `/autosticker` · `/ban` · `/captcha` · `/cat` · `/catimg` · `/catprompt` · `/catprompt reset` · `/dado` · `/down` · `/farewell` · `/groups` · `/info` · `/invite` · `/join` · `/leave` · `/menu anime` · `/menu figurinhas` · `/menu ia` · `/menu midia` · `/menu quote` · `/menu stats` · `/menuadm` · `/metadata` · `/newgroup` · `/noticias` · `/nsfw` · `/pack add` · `/pack create` · `/pack list` · `/pack send` · `/ping` · `/play` · `/playvid` · `/prefix` · `/premium` · `/quote` · `/ranking` · `/rankingglobal` · `/requests` · `/revoke` · `/s` · `/semmsg` · `/setdesc` · `/setgroup` · `/setsubject` · `/st` · `/stb` · `/sticker` · `/stickertext` · `/stickertextblink` · `/stickertextwhite` · `/stw` · `/temp` · `/tiktok` · `/toimg` · `/up` · `/updaterequests` · `/user perfil` · `/welcome`
81
+
82
+ </details>
83
+ <!-- README_SNAPSHOT:END -->
84
+
47
85
  ## Recursos principais
48
86
 
49
87
  - Gerenciamento de grupos (admin, boas-vindas, despedida, anti-link, captcha).
@@ -150,6 +188,7 @@ Variáveis legadas foram mantidas por compatibilidade (`QUOTE_API_URL`, `WAIFU_A
150
188
  - `npm run pm2:prod`: sobe com PM2 usando `ecosystem.prod.config.cjs`.
151
189
  - `npm run deploy`: deploy automático de `public/` com cache-bust, backup, validação e reload do Nginx.
152
190
  - `npm run deploy:dry-run`: simula o deploy sem publicar/recarregar serviços.
191
+ - `npm run readme:sync-snapshot`: sincroniza o bloco dinâmico do README consumindo `/api/sticker-packs/readme-markdown`.
153
192
  - `npm run release`: release completo com versão unificada (npmjs + GitHub Packages + GitHub Release) e verificação final.
154
193
  - `npm run release:minor`: bump `minor` + deploy + publish do package.
155
194
  - `npm run release:major`: bump `major` + deploy + publish do package.
@@ -256,6 +295,9 @@ Variáveis do fluxo de release (git):
256
295
  - `RELEASE_GIT_BRANCH` (opcional; vazio usa branch atual)
257
296
  - `RELEASE_GIT_PRE_COMMIT_MESSAGE` (default: `chore(release): auto-commit before release`)
258
297
  - `RELEASE_GIT_COMMIT_VERSION` (default: `1`) - commita alteração da versão após sucesso
298
+ - `RELEASE_README_SYNC` (default: `1`) - sincroniza bloco dinâmico do README via API antes do commit/tag
299
+ - `RELEASE_README_SYNC_REQUIRED` (default: `0`) - se `1`, falha o release quando a sincronização do README falhar
300
+ - `RELEASE_README_SYNC_COMMAND` (default: `npm run readme:sync-snapshot`) - comando customizável para sincronização
259
301
  - `RELEASE_GIT_VERSION_COMMIT_PREFIX` (default: `chore(release): v`)
260
302
  - `RELEASE_GIT_TAG_CREATE` (default: `1`) - cria tag `vX.Y.Z` no release
261
303
  - `RELEASE_GIT_TAG_PUSH` (default: `1`) - envia a tag para o remoto
@@ -9,7 +9,7 @@ import { handleRankingCommand } from '../modules/statsModule/rankingCommand.js';
9
9
  import { handleGlobalRankingCommand } from '../modules/statsModule/globalRankingCommand.js';
10
10
  import { handleNoMessageCommand } from '../modules/statsModule/noMessageCommand.js';
11
11
  import { handlePingCommand } from '../modules/systemMetricsModule/pingCommand.js';
12
- import { extractMessageContent, getExpiration, isGroupJid, isSameJidUser, resolveBotJid } from '../config/baileysConfig.js';
12
+ import { extractMessageContent, getExpiration, getJidServer, getJidUser, isGroupJid, isSameJidUser, normalizeJid, resolveBotJid } from '../config/baileysConfig.js';
13
13
  import logger from '../utils/logger/loggerModule.js';
14
14
  import { handleAntiLink } from '../utils/antiLink/antiLinkModule.js';
15
15
  import { handleCatCommand, handleCatImageCommand, handleCatPromptCommand } from '../modules/aiModule/catCommand.js';
@@ -25,9 +25,125 @@ import { handleRpgPokemonCommand } from '../modules/rpgPokemonModule/rpgPokemonC
25
25
  import groupConfigStore from '../store/groupConfigStore.js';
26
26
  import { sendAndStore } from '../services/messagePersistenceService.js';
27
27
  import { resolveCaptchaByMessage } from '../services/captchaService.js';
28
+ import { extractSenderInfoFromMessage, resolveUserId } from '../services/lidMapService.js';
29
+ import { buildWhatsAppGoogleLoginUrl } from '../services/whatsappLoginLinkService.js';
28
30
 
29
31
  const DEFAULT_COMMAND_PREFIX = process.env.COMMAND_PREFIX || '/';
30
32
  const COMMAND_REACT_EMOJI = process.env.COMMAND_REACT_EMOJI || '🤖';
33
+ const START_LOGIN_TRIGGER = String(process.env.WHATSAPP_LOGIN_TRIGGER || 'iniciar')
34
+ .trim()
35
+ .toLowerCase() || 'iniciar';
36
+ const WHATSAPP_USER_SERVERS = new Set(['s.whatsapp.net', 'c.us', 'hosted']);
37
+ const WHATSAPP_LID_SERVERS = new Set(['lid', 'hosted.lid']);
38
+
39
+ const normalizeTriggerText = (value) =>
40
+ String(value || '')
41
+ .trim()
42
+ .toLowerCase()
43
+ .normalize('NFD')
44
+ .replace(/[\u0300-\u036f]/g, '');
45
+
46
+ const isStartLoginTrigger = (text) => normalizeTriggerText(text) === START_LOGIN_TRIGGER;
47
+
48
+ const resolveCanonicalWhatsAppJid = (...candidates) => {
49
+ for (const candidate of candidates) {
50
+ const normalized = normalizeJid(String(candidate || '').trim());
51
+ if (!normalized) continue;
52
+ const server = getJidServer(normalized);
53
+ if (!WHATSAPP_USER_SERVERS.has(server) && !WHATSAPP_LID_SERVERS.has(server)) continue;
54
+ const user = String(getJidUser(normalized) || '')
55
+ .split(':')[0]
56
+ .replace(/\D+/g, '');
57
+ if (!user) continue;
58
+ if (user.length < 10 || user.length > 15) continue;
59
+ return normalizeJid(`${user}@s.whatsapp.net`) || normalized;
60
+ }
61
+ return '';
62
+ };
63
+
64
+ const maybeHandleStartLoginMessage = async ({
65
+ sock,
66
+ messageInfo,
67
+ extractedText,
68
+ senderName,
69
+ senderJid,
70
+ remoteJid,
71
+ expirationMessage,
72
+ isMessageFromBot,
73
+ isGroupMessage,
74
+ }) => {
75
+ if (isMessageFromBot || !isStartLoginTrigger(extractedText)) return false;
76
+
77
+ if (isGroupMessage) {
78
+ await sendAndStore(
79
+ sock,
80
+ remoteJid,
81
+ {
82
+ text: 'Por seguranca, envie *iniciar* no privado do bot para receber seu link de login.',
83
+ },
84
+ { quoted: messageInfo, ephemeralExpiration: expirationMessage },
85
+ );
86
+ return true;
87
+ }
88
+
89
+ const key = messageInfo?.key || {};
90
+ const senderInfo = extractSenderInfoFromMessage(messageInfo);
91
+ let canonicalUserId = resolveCanonicalWhatsAppJid(
92
+ senderInfo?.jid,
93
+ senderInfo?.lid,
94
+ senderInfo?.participantAlt,
95
+ key.participantAlt,
96
+ key.participant,
97
+ key.remoteJid,
98
+ senderJid,
99
+ );
100
+ try {
101
+ const resolvedUserId = await resolveUserId(senderInfo);
102
+ canonicalUserId = resolveCanonicalWhatsAppJid(resolvedUserId, canonicalUserId, senderInfo?.jid, senderInfo?.lid);
103
+ } catch (error) {
104
+ logger.warn('Falha ao resolver ID canonico para fluxo de login do WhatsApp.', {
105
+ error: error?.message,
106
+ });
107
+ }
108
+
109
+ const loginUrl = buildWhatsAppGoogleLoginUrl({ userId: canonicalUserId });
110
+ if (!loginUrl) {
111
+ logger.warn('Nao foi possivel montar link de login para mensagem "iniciar".', {
112
+ action: 'login_link_missing_user_phone',
113
+ remoteServer: getJidServer(key.remoteJid || ''),
114
+ participantServer: getJidServer(key.participant || ''),
115
+ participantAltServer: getJidServer(key.participantAlt || ''),
116
+ hasLid: Boolean(senderInfo?.lid),
117
+ hasJid: Boolean(senderInfo?.jid),
118
+ });
119
+ await sendAndStore(
120
+ sock,
121
+ remoteJid,
122
+ {
123
+ text: 'Nao consegui identificar seu numero de WhatsApp para o login. Tente novamente em alguns segundos.',
124
+ },
125
+ { quoted: messageInfo, ephemeralExpiration: expirationMessage },
126
+ );
127
+ return true;
128
+ }
129
+
130
+ const safeName = String(senderName || '').trim();
131
+ const greeting = safeName ? `Oi, *${safeName}*!` : 'Oi!';
132
+ await sendAndStore(
133
+ sock,
134
+ remoteJid,
135
+ {
136
+ text:
137
+ `${greeting}\n\n` +
138
+ 'Para continuar no OmniZap, faca login com Google neste link:\n' +
139
+ `${loginUrl}\n\n` +
140
+ 'Seu numero do WhatsApp sera vinculado automaticamente a conta logada.',
141
+ },
142
+ { quoted: messageInfo, ephemeralExpiration: expirationMessage },
143
+ );
144
+
145
+ return true;
146
+ };
31
147
 
32
148
  /**
33
149
  * Resolve o prefixo de comandos.
@@ -111,6 +227,22 @@ export const handleMessages = async (update, sock) => {
111
227
  });
112
228
  }
113
229
 
230
+ const handledStartLogin = await maybeHandleStartLoginMessage({
231
+ sock,
232
+ messageInfo,
233
+ extractedText,
234
+ senderName,
235
+ senderJid,
236
+ remoteJid,
237
+ expirationMessage,
238
+ isMessageFromBot,
239
+ isGroupMessage,
240
+ });
241
+
242
+ if (handledStartLogin) {
243
+ continue;
244
+ }
245
+
114
246
  /**
115
247
  * Envia uma reação automática quando a mensagem começa com o prefixo de comando.
116
248
  * A falha no envio da reação não interrompe o processamento do comando.