@kaikybrofc/omnizap-system 2.3.2 → 2.3.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/README.md +82 -487
- package/app/modules/stickerModule/stickerCommand.js +7 -2
- package/app/modules/stickerModule/stickerTextCommand.js +7 -2
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +224 -53
- package/app/services/lidMapService.js +83 -4
- package/package.json +1 -1
- package/public/api-docs/index.html +3 -2
- package/public/apple-touch-icon.png +0 -0
- package/public/bot-whatsapp-para-grupo/index.html +3 -1
- package/public/bot-whatsapp-sem-programar/index.html +3 -1
- package/public/comandos/index.html +3 -2
- package/public/como-automatizar-avisos-no-whatsapp/index.html +3 -1
- package/public/como-criar-comandos-whatsapp/index.html +3 -1
- package/public/como-evitar-spam-no-whatsapp/index.html +3 -1
- package/public/como-moderar-grupo-whatsapp/index.html +3 -1
- package/public/como-organizar-comunidade-whatsapp/index.html +3 -1
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +3 -2
- package/public/js/apps/createPackApp.js +4 -4
- package/public/js/apps/homeApp.js +4 -5
- package/public/js/apps/loginApp.js +83 -28
- package/public/js/apps/stickersAdminApp.js +1 -1
- package/public/js/apps/stickersApp.js +1 -1
- package/public/js/apps/userApp.js +8 -37
- package/public/licenca/index.html +3 -2
- package/public/login/index.html +20 -12
- package/public/melhor-bot-whatsapp-para-grupos/index.html +3 -1
- package/public/site.webmanifest +24 -0
- package/public/stickers/create/index.html +3 -1
- package/public/stickers/index.html +3 -1
- package/public/termos-de-uso/index.html +3 -2
- package/public/user/index.html +3 -2
- package/public/user/systemadm/index.html +3 -1
- package/server/controllers/stickerCatalog/nonCatalogHandlers.js +1 -26
- package/server/controllers/stickerCatalogController.js +161 -63
- package/server/middleware/cachePolicyHelpers.js +1 -2
- package/server/middleware/rateLimit.js +9 -2
- package/server/routes/indexRouter.js +1 -7
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import logger from '../../utils/logger/loggerModule.js';
|
|
2
2
|
import { sendAndStore } from '../../services/messagePersistenceService.js';
|
|
3
|
-
import { isUserJid } from '../../config/baileysConfig.js';
|
|
3
|
+
import { getJidServer, isUserJid, normalizeJid } from '../../config/baileysConfig.js';
|
|
4
4
|
import stickerPackService from './stickerPackServiceRuntime.js';
|
|
5
5
|
import { STICKER_PACK_ERROR_CODES, StickerPackError } from './stickerPackErrors.js';
|
|
6
6
|
import { captureIncomingStickerAsset, resolveStickerAssetForCommand } from './stickerStorageService.js';
|
|
7
7
|
import { buildStickerPackMessage, sendStickerPackWithFallback } from './stickerPackMessageService.js';
|
|
8
8
|
import { sanitizeText } from './stickerPackUtils.js';
|
|
9
|
+
import { executeQuery, TABLES } from '../../../database/index.js';
|
|
10
|
+
import { extractSenderInfoFromMessage, extractUserIdInfo, resolveUserId } from '../../services/lidMapService.js';
|
|
11
|
+
import { toWhatsAppPhoneDigits } from '../../services/whatsappLoginLinkService.js';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Handlers de comando textual para gerenciamento de packs de figurinha.
|
|
@@ -14,6 +17,7 @@ const RATE_WINDOW_MS = Math.max(10_000, Number(process.env.STICKER_PACK_RATE_WIN
|
|
|
14
17
|
const RATE_MAX_ACTIONS = Math.max(1, Number(process.env.STICKER_PACK_RATE_MAX_ACTIONS) || 20);
|
|
15
18
|
const MAX_PACK_ITEMS = Math.max(1, Number(process.env.STICKER_PACK_MAX_ITEMS) || 30);
|
|
16
19
|
const MAX_PACK_NAME_LENGTH = 120;
|
|
20
|
+
const LID_SERVERS = new Set(['lid', 'hosted.lid']);
|
|
17
21
|
|
|
18
22
|
const rateMap = new Map();
|
|
19
23
|
|
|
@@ -159,20 +163,23 @@ const formatVisibilityLabel = (visibility) => {
|
|
|
159
163
|
};
|
|
160
164
|
|
|
161
165
|
/**
|
|
162
|
-
* Detecta packs automáticos para ocultar em listagens
|
|
166
|
+
* Detecta packs automáticos de curadoria temática para ocultar em listagens padrão.
|
|
167
|
+
* Mantém visível o auto-pack coletor do usuário (ex.: "minhasfigurinhas1").
|
|
163
168
|
*
|
|
164
169
|
* @param {object|null|undefined} pack Pack retornado pelo serviço.
|
|
165
|
-
* @returns {boolean} Verdadeiro quando
|
|
170
|
+
* @returns {boolean} Verdadeiro quando for auto-pack temático/curadoria.
|
|
166
171
|
*/
|
|
167
|
-
const
|
|
172
|
+
const isThemeCurationPack = (pack) => {
|
|
168
173
|
if (!pack || typeof pack !== 'object') return false;
|
|
169
|
-
if (pack.is_auto_pack === true || Number(pack.is_auto_pack || 0) === 1) return true;
|
|
170
174
|
|
|
171
175
|
const name = String(pack.name || '').trim();
|
|
172
176
|
if (/^\[auto\]/i.test(name)) return true;
|
|
173
177
|
|
|
174
178
|
const description = String(pack.description || '').toLowerCase();
|
|
175
|
-
|
|
179
|
+
if (description.includes('[auto-theme:') || description.includes('[auto-tag:')) return true;
|
|
180
|
+
|
|
181
|
+
const themeKey = String(pack.pack_theme_key || '').trim();
|
|
182
|
+
return Boolean(themeKey);
|
|
176
183
|
};
|
|
177
184
|
|
|
178
185
|
/**
|
|
@@ -448,6 +455,142 @@ const readSingleArgument = (input) => {
|
|
|
448
455
|
return value ? value : null;
|
|
449
456
|
};
|
|
450
457
|
|
|
458
|
+
const buildOwnerLookupJids = (value) => {
|
|
459
|
+
const normalized = normalizeJid(value) || '';
|
|
460
|
+
if (!normalized || !normalized.includes('@')) return [];
|
|
461
|
+
const lookup = new Set([normalized]);
|
|
462
|
+
const digits = toWhatsAppPhoneDigits(normalized);
|
|
463
|
+
if (!digits) return Array.from(lookup);
|
|
464
|
+
lookup.add(normalizeJid(`${digits}@s.whatsapp.net`) || '');
|
|
465
|
+
lookup.add(normalizeJid(`${digits}@c.us`) || '');
|
|
466
|
+
lookup.add(normalizeJid(`${digits}@hosted`) || '');
|
|
467
|
+
return Array.from(lookup).filter(Boolean);
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
const appendOwnerCandidate = (candidateSet, lookupSet, value) => {
|
|
471
|
+
const normalized = normalizeJid(value) || '';
|
|
472
|
+
if (!normalized || !normalized.includes('@')) return;
|
|
473
|
+
candidateSet.add(normalized);
|
|
474
|
+
for (const lookupJid of buildOwnerLookupJids(normalized)) {
|
|
475
|
+
lookupSet.add(lookupJid);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const dedupePacksById = (packs = []) => {
|
|
480
|
+
const dedup = new Map();
|
|
481
|
+
for (const pack of Array.isArray(packs) ? packs : []) {
|
|
482
|
+
if (!pack?.id) continue;
|
|
483
|
+
const existing = dedup.get(pack.id);
|
|
484
|
+
if (!existing) {
|
|
485
|
+
dedup.set(pack.id, pack);
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
const currentUpdatedAt = Date.parse(String(pack.updated_at || pack.created_at || ''));
|
|
489
|
+
const existingUpdatedAt = Date.parse(String(existing.updated_at || existing.created_at || ''));
|
|
490
|
+
if (Number.isFinite(currentUpdatedAt) && (!Number.isFinite(existingUpdatedAt) || currentUpdatedAt > existingUpdatedAt)) {
|
|
491
|
+
dedup.set(pack.id, pack);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return Array.from(dedup.values()).sort((a, b) => {
|
|
496
|
+
const aUpdatedAt = Date.parse(String(a?.updated_at || a?.created_at || ''));
|
|
497
|
+
const bUpdatedAt = Date.parse(String(b?.updated_at || b?.created_at || ''));
|
|
498
|
+
if (!Number.isFinite(aUpdatedAt) && !Number.isFinite(bUpdatedAt)) return 0;
|
|
499
|
+
if (!Number.isFinite(aUpdatedAt)) return 1;
|
|
500
|
+
if (!Number.isFinite(bUpdatedAt)) return -1;
|
|
501
|
+
return bUpdatedAt - aUpdatedAt;
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const resolveOwnerCandidatesForPackCommand = async ({ senderJid, messageInfo }) => {
|
|
506
|
+
const candidates = new Set();
|
|
507
|
+
const lookupByJid = new Set();
|
|
508
|
+
|
|
509
|
+
const senderInfo = extractSenderInfoFromMessage(messageInfo);
|
|
510
|
+
appendOwnerCandidate(candidates, lookupByJid, senderJid);
|
|
511
|
+
appendOwnerCandidate(candidates, lookupByJid, senderInfo?.jid);
|
|
512
|
+
appendOwnerCandidate(candidates, lookupByJid, senderInfo?.participantAlt);
|
|
513
|
+
appendOwnerCandidate(candidates, lookupByJid, senderInfo?.lid);
|
|
514
|
+
|
|
515
|
+
const directResolved = await resolveUserId(extractUserIdInfo(senderJid)).catch(() => null);
|
|
516
|
+
if (directResolved) {
|
|
517
|
+
appendOwnerCandidate(candidates, lookupByJid, directResolved);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const senderResolved = await resolveUserId({
|
|
521
|
+
lid: senderInfo?.lid,
|
|
522
|
+
jid: senderInfo?.jid || senderJid || null,
|
|
523
|
+
participantAlt: senderInfo?.participantAlt || null,
|
|
524
|
+
}).catch(() => null);
|
|
525
|
+
if (senderResolved) {
|
|
526
|
+
appendOwnerCandidate(candidates, lookupByJid, senderResolved);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const lookupValues = Array.from(lookupByJid).filter(Boolean);
|
|
530
|
+
for (let offset = 0; offset < lookupValues.length; offset += 200) {
|
|
531
|
+
const chunk = lookupValues.slice(offset, offset + 200);
|
|
532
|
+
if (!chunk.length) continue;
|
|
533
|
+
const placeholders = chunk.map(() => '?').join(', ');
|
|
534
|
+
const lookupParams = [...chunk, ...chunk];
|
|
535
|
+
const rows = await executeQuery(
|
|
536
|
+
`SELECT lid, jid
|
|
537
|
+
FROM ${TABLES.LID_MAP}
|
|
538
|
+
WHERE jid IN (${placeholders})
|
|
539
|
+
OR lid IN (${placeholders})
|
|
540
|
+
ORDER BY last_seen DESC
|
|
541
|
+
LIMIT 500`,
|
|
542
|
+
lookupParams,
|
|
543
|
+
).catch(() => []);
|
|
544
|
+
|
|
545
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
546
|
+
appendOwnerCandidate(candidates, lookupByJid, row?.jid || '');
|
|
547
|
+
appendOwnerCandidate(candidates, lookupByJid, row?.lid || '');
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const lidCandidates = Array.from(candidates).filter((candidate) => LID_SERVERS.has(getJidServer(candidate)));
|
|
552
|
+
for (const lidValue of lidCandidates) {
|
|
553
|
+
const resolved = await resolveUserId(extractUserIdInfo(lidValue)).catch(() => null);
|
|
554
|
+
if (resolved) {
|
|
555
|
+
appendOwnerCandidate(candidates, lookupByJid, resolved);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return Array.from(candidates);
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
const pickPrimaryOwnerCandidate = (ownerCandidates, senderJid) => {
|
|
563
|
+
const preferred = (Array.isArray(ownerCandidates) ? ownerCandidates : []).find((candidate) => {
|
|
564
|
+
const server = getJidServer(candidate);
|
|
565
|
+
if (!server || LID_SERVERS.has(server)) return false;
|
|
566
|
+
return server !== 'google.oauth';
|
|
567
|
+
});
|
|
568
|
+
if (preferred) return preferred;
|
|
569
|
+
|
|
570
|
+
const normalizedSender = normalizeJid(senderJid) || '';
|
|
571
|
+
if (normalizedSender) return normalizedSender;
|
|
572
|
+
return Array.isArray(ownerCandidates) && ownerCandidates.length ? ownerCandidates[0] : senderJid;
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
const runWithOwnerFallback = async (ownerCandidates, action) => {
|
|
576
|
+
const owners = Array.isArray(ownerCandidates) && ownerCandidates.length ? ownerCandidates : [];
|
|
577
|
+
let notFoundError = null;
|
|
578
|
+
for (const candidateOwner of owners) {
|
|
579
|
+
try {
|
|
580
|
+
return await action(candidateOwner);
|
|
581
|
+
} catch (error) {
|
|
582
|
+
if (error instanceof StickerPackError && error.code === STICKER_PACK_ERROR_CODES.PACK_NOT_FOUND) {
|
|
583
|
+
notFoundError = notFoundError || error;
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
throw error;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (notFoundError) throw notFoundError;
|
|
591
|
+
throw new StickerPackError(STICKER_PACK_ERROR_CODES.PACK_NOT_FOUND, 'Pack não encontrado para este usuário.');
|
|
592
|
+
};
|
|
593
|
+
|
|
451
594
|
/**
|
|
452
595
|
* Normaliza e valida nome de pack (permite espaços e emojis).
|
|
453
596
|
*
|
|
@@ -530,7 +673,9 @@ const resolveStickerFromCommandContext = async ({ messageInfo, ownerJid, include
|
|
|
530
673
|
* @returns {Promise<void>}
|
|
531
674
|
*/
|
|
532
675
|
export async function handlePackCommand({ sock, remoteJid, messageInfo, expirationMessage, senderJid, senderName, text, commandPrefix }) {
|
|
533
|
-
const
|
|
676
|
+
const ownerCandidatesRaw = await resolveOwnerCandidatesForPackCommand({ senderJid, messageInfo }).catch(() => []);
|
|
677
|
+
const ownerJid = pickPrimaryOwnerCandidate(ownerCandidatesRaw, senderJid);
|
|
678
|
+
const ownerCandidates = Array.from(new Set([ownerJid, ...ownerCandidatesRaw].filter(Boolean)));
|
|
534
679
|
const rate = checkRateLimit(ownerJid);
|
|
535
680
|
|
|
536
681
|
if (rate.limited) {
|
|
@@ -590,8 +735,9 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
590
735
|
}
|
|
591
736
|
|
|
592
737
|
case 'list': {
|
|
593
|
-
const
|
|
594
|
-
const
|
|
738
|
+
const packLists = await Promise.all(ownerCandidates.map((candidateOwner) => stickerPackService.listPacks({ ownerJid: candidateOwner, limit: 100 })));
|
|
739
|
+
const packs = dedupePacksById(packLists.flatMap((items) => (Array.isArray(items) ? items : [])));
|
|
740
|
+
const manualPacks = packs.filter((pack) => !isThemeCurationPack(pack));
|
|
595
741
|
|
|
596
742
|
await sendReply({
|
|
597
743
|
sock,
|
|
@@ -605,7 +751,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
605
751
|
|
|
606
752
|
case 'info': {
|
|
607
753
|
const identifier = readSingleArgument(rest);
|
|
608
|
-
const pack = await stickerPackService.getPackInfo({ ownerJid, identifier });
|
|
754
|
+
const pack = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.getPackInfo({ ownerJid: candidateOwner, identifier }));
|
|
609
755
|
|
|
610
756
|
await sendReply({
|
|
611
757
|
sock,
|
|
@@ -620,7 +766,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
620
766
|
case 'rename': {
|
|
621
767
|
const { identifier, value } = parseIdentifierAndValue(rest);
|
|
622
768
|
const normalizedName = normalizePackName(value, { label: 'Novo nome do pack' });
|
|
623
|
-
const updated = await stickerPackService.renamePack({ ownerJid, identifier, name: normalizedName });
|
|
769
|
+
const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.renamePack({ ownerJid: candidateOwner, identifier, name: normalizedName }));
|
|
624
770
|
|
|
625
771
|
await sendReply({
|
|
626
772
|
sock,
|
|
@@ -639,7 +785,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
639
785
|
|
|
640
786
|
case 'setpub': {
|
|
641
787
|
const { identifier, value } = parseIdentifierAndValue(rest);
|
|
642
|
-
const updated = await stickerPackService.setPackPublisher({ ownerJid, identifier, publisher: value });
|
|
788
|
+
const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.setPackPublisher({ ownerJid: candidateOwner, identifier, publisher: value }));
|
|
643
789
|
|
|
644
790
|
await sendReply({
|
|
645
791
|
sock,
|
|
@@ -659,7 +805,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
659
805
|
case 'setdesc': {
|
|
660
806
|
const { identifier, value } = parseIdentifierAndValue(rest);
|
|
661
807
|
const description = value === '-' || value.toLowerCase() === 'clear' ? '' : value;
|
|
662
|
-
const updated = await stickerPackService.setPackDescription({ ownerJid, identifier, description });
|
|
808
|
+
const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.setPackDescription({ ownerJid: candidateOwner, identifier, description }));
|
|
663
809
|
|
|
664
810
|
await sendReply({
|
|
665
811
|
sock,
|
|
@@ -684,11 +830,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
684
830
|
throw new StickerPackError(STICKER_PACK_ERROR_CODES.STICKER_NOT_FOUND, 'Não encontrei uma figurinha para definir como capa.');
|
|
685
831
|
}
|
|
686
832
|
|
|
687
|
-
const updated = await
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
833
|
+
const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
|
|
834
|
+
stickerPackService.setPackCover({
|
|
835
|
+
ownerJid: candidateOwner,
|
|
836
|
+
identifier,
|
|
837
|
+
stickerId: asset.id,
|
|
838
|
+
}),
|
|
839
|
+
);
|
|
692
840
|
|
|
693
841
|
await sendReply({
|
|
694
842
|
sock,
|
|
@@ -715,13 +863,15 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
715
863
|
throw new StickerPackError(STICKER_PACK_ERROR_CODES.STICKER_NOT_FOUND, 'Não encontrei uma figurinha para adicionar.');
|
|
716
864
|
}
|
|
717
865
|
|
|
718
|
-
const updated = await
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
866
|
+
const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
|
|
867
|
+
stickerPackService.addStickerToPack({
|
|
868
|
+
ownerJid: candidateOwner,
|
|
869
|
+
identifier,
|
|
870
|
+
asset,
|
|
871
|
+
emojis: options.emojis,
|
|
872
|
+
accessibilityLabel: options.label || options.accessibility || null,
|
|
873
|
+
}),
|
|
874
|
+
);
|
|
725
875
|
|
|
726
876
|
await sendReply({
|
|
727
877
|
sock,
|
|
@@ -742,11 +892,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
742
892
|
const { token: identifier, rest: selectorRest } = readToken(rest);
|
|
743
893
|
const { token: selector } = readToken(selectorRest);
|
|
744
894
|
|
|
745
|
-
const result = await
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
895
|
+
const result = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
|
|
896
|
+
stickerPackService.removeStickerFromPack({
|
|
897
|
+
ownerJid: candidateOwner,
|
|
898
|
+
identifier,
|
|
899
|
+
selector,
|
|
900
|
+
}),
|
|
901
|
+
);
|
|
750
902
|
|
|
751
903
|
await sendReply({
|
|
752
904
|
sock,
|
|
@@ -765,16 +917,18 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
765
917
|
|
|
766
918
|
case 'reorder': {
|
|
767
919
|
const { token: identifier, rest: rawOrder } = readToken(rest);
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
920
|
+
const updated = await runWithOwnerFallback(ownerCandidates, async (candidateOwner) => {
|
|
921
|
+
const orderStickerIds = await parseReorderInput({
|
|
922
|
+
ownerJid: candidateOwner,
|
|
923
|
+
identifier,
|
|
924
|
+
rawOrder,
|
|
925
|
+
});
|
|
773
926
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
927
|
+
return stickerPackService.reorderPackItems({
|
|
928
|
+
ownerJid: candidateOwner,
|
|
929
|
+
identifier,
|
|
930
|
+
orderStickerIds,
|
|
931
|
+
});
|
|
778
932
|
});
|
|
779
933
|
|
|
780
934
|
await sendReply({
|
|
@@ -796,11 +950,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
796
950
|
const { token: identifier, rest: cloneNameRaw } = readToken(rest);
|
|
797
951
|
const cloneName = normalizePackName(cloneNameRaw, { label: 'Novo nome do clone' });
|
|
798
952
|
|
|
799
|
-
const cloned = await
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
953
|
+
const cloned = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
|
|
954
|
+
stickerPackService.clonePack({
|
|
955
|
+
ownerJid: candidateOwner,
|
|
956
|
+
identifier,
|
|
957
|
+
newName: cloneName,
|
|
958
|
+
}),
|
|
959
|
+
);
|
|
804
960
|
|
|
805
961
|
await sendReply({
|
|
806
962
|
sock,
|
|
@@ -819,7 +975,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
819
975
|
|
|
820
976
|
case 'delete': {
|
|
821
977
|
const identifier = readSingleArgument(rest);
|
|
822
|
-
const deleted = await stickerPackService.deletePack({ ownerJid, identifier });
|
|
978
|
+
const deleted = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.deletePack({ ownerJid: candidateOwner, identifier }));
|
|
823
979
|
|
|
824
980
|
await sendReply({
|
|
825
981
|
sock,
|
|
@@ -840,11 +996,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
840
996
|
const { token: identifier, rest: visibilityRaw } = readToken(rest);
|
|
841
997
|
const visibility = unquote(visibilityRaw);
|
|
842
998
|
|
|
843
|
-
const updated = await
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
999
|
+
const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
|
|
1000
|
+
stickerPackService.setPackVisibility({
|
|
1001
|
+
ownerJid: candidateOwner,
|
|
1002
|
+
identifier,
|
|
1003
|
+
visibility,
|
|
1004
|
+
}),
|
|
1005
|
+
);
|
|
848
1006
|
|
|
849
1007
|
await sendReply({
|
|
850
1008
|
sock,
|
|
@@ -863,7 +1021,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
|
|
|
863
1021
|
|
|
864
1022
|
case 'send': {
|
|
865
1023
|
const identifier = readSingleArgument(rest);
|
|
866
|
-
const packDetails = await stickerPackService.getPackInfoForSend({ ownerJid, identifier });
|
|
1024
|
+
const packDetails = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.getPackInfoForSend({ ownerJid: candidateOwner, identifier }));
|
|
867
1025
|
const packBuild = await buildStickerPackMessage(packDetails);
|
|
868
1026
|
const sendResult = await sendStickerPackWithFallback({
|
|
869
1027
|
sock,
|
|
@@ -942,15 +1100,28 @@ export async function maybeCaptureIncomingSticker({ messageInfo, senderJid, isMe
|
|
|
942
1100
|
if (isMessageFromBot) return null;
|
|
943
1101
|
if (!isUserJid(senderJid)) return null;
|
|
944
1102
|
|
|
1103
|
+
const senderInfo = extractSenderInfoFromMessage(messageInfo);
|
|
1104
|
+
let ownerJid = normalizeJid(senderJid) || senderJid;
|
|
1105
|
+
try {
|
|
1106
|
+
const resolvedOwner = await resolveUserId({
|
|
1107
|
+
lid: senderInfo?.lid,
|
|
1108
|
+
jid: senderInfo?.jid || senderJid || null,
|
|
1109
|
+
participantAlt: senderInfo?.participantAlt || null,
|
|
1110
|
+
});
|
|
1111
|
+
ownerJid = normalizeJid(resolvedOwner || ownerJid) || ownerJid;
|
|
1112
|
+
} catch {
|
|
1113
|
+
ownerJid = normalizeJid(senderJid) || senderJid;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
945
1116
|
try {
|
|
946
1117
|
return await captureIncomingStickerAsset({
|
|
947
1118
|
messageInfo,
|
|
948
|
-
ownerJid
|
|
1119
|
+
ownerJid,
|
|
949
1120
|
});
|
|
950
1121
|
} catch (error) {
|
|
951
1122
|
logger.warn('Falha ao capturar figurinha recebida para storage.', {
|
|
952
1123
|
action: 'pack_capture_warning',
|
|
953
|
-
owner_jid:
|
|
1124
|
+
owner_jid: ownerJid,
|
|
954
1125
|
error: error.message,
|
|
955
1126
|
});
|
|
956
1127
|
return null;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
1
4
|
import logger from '../utils/logger/loggerModule.js';
|
|
2
5
|
import { executeQuery, TABLES } from '../../database/index.js';
|
|
3
6
|
import { getJidServer, normalizeJid, isGroupJid } from '../config/baileysConfig.js';
|
|
@@ -10,12 +13,16 @@ const STORE_COOLDOWN_MS = 10 * 60 * 1000;
|
|
|
10
13
|
const BATCH_LIMIT = 800;
|
|
11
14
|
const BACKFILL_DEFAULT_BATCH = 50000;
|
|
12
15
|
const BACKFILL_SOURCE = 'backfill';
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
18
|
+
const BAILEYS_AUTH_DIR = path.resolve(__dirname, '../connection/auth');
|
|
13
19
|
|
|
14
20
|
const LID_SERVERS = new Set(['lid', 'hosted.lid']);
|
|
15
21
|
const PN_SERVERS = new Set(['s.whatsapp.net', 'c.us', 'hosted']);
|
|
16
22
|
|
|
17
23
|
const lidCache = new Map();
|
|
18
24
|
const lidWriteBuffer = new Map();
|
|
25
|
+
const authReverseLidCache = new Map();
|
|
19
26
|
|
|
20
27
|
let backfillPromise = null;
|
|
21
28
|
|
|
@@ -55,6 +62,54 @@ const normalizeWhatsAppJid = (jid) => {
|
|
|
55
62
|
return normalized || null;
|
|
56
63
|
};
|
|
57
64
|
|
|
65
|
+
const toDigits = (value) => String(value || '').replace(/\D+/g, '');
|
|
66
|
+
|
|
67
|
+
const parseReverseMappingPhoneDigits = (content) => {
|
|
68
|
+
const raw = String(content || '').trim();
|
|
69
|
+
if (!raw) return '';
|
|
70
|
+
|
|
71
|
+
let parsed = raw;
|
|
72
|
+
try {
|
|
73
|
+
parsed = JSON.parse(raw);
|
|
74
|
+
} catch {
|
|
75
|
+
parsed = raw;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const digits = toDigits(parsed);
|
|
79
|
+
return digits.length >= 10 && digits.length <= 15 ? digits : '';
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const resolveAuthStoreJidByLid = async (lid) => {
|
|
83
|
+
const normalizedLid = normalizeLid(lid);
|
|
84
|
+
if (!normalizedLid) return null;
|
|
85
|
+
|
|
86
|
+
const [rawUser] = normalizedLid.split('@');
|
|
87
|
+
const rootUser = rawUser ? rawUser.split(':')[0] : '';
|
|
88
|
+
if (!rootUser || !/^\d+$/.test(rootUser)) return null;
|
|
89
|
+
|
|
90
|
+
if (authReverseLidCache.has(rootUser)) {
|
|
91
|
+
return authReverseLidCache.get(rootUser);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const reverseFilePath = path.join(BAILEYS_AUTH_DIR, `lid-mapping-${rootUser}_reverse.json`);
|
|
95
|
+
try {
|
|
96
|
+
const content = await readFile(reverseFilePath, 'utf8');
|
|
97
|
+
const phoneDigits = parseReverseMappingPhoneDigits(content);
|
|
98
|
+
const resolvedJid = phoneDigits ? normalizeWhatsAppJid(`${phoneDigits}@s.whatsapp.net`) : null;
|
|
99
|
+
authReverseLidCache.set(rootUser, resolvedJid);
|
|
100
|
+
return resolvedJid;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (error?.code !== 'ENOENT') {
|
|
103
|
+
logger.warn('Falha ao resolver LID via auth store local.', {
|
|
104
|
+
lid: normalizedLid,
|
|
105
|
+
error: error?.message,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
authReverseLidCache.set(rootUser, null);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
58
113
|
/**
|
|
59
114
|
* Mascara um JID para logs.
|
|
60
115
|
* @param {string|null|undefined} jid
|
|
@@ -191,8 +246,21 @@ export const primeLidCache = async (lids = []) => {
|
|
|
191
246
|
const base = baseByLid.get(lid);
|
|
192
247
|
const direct = rowMap.has(lid) ? rowMap.get(lid) : undefined;
|
|
193
248
|
const baseValue = base && base !== lid && rowMap.has(base) ? rowMap.get(base) : undefined;
|
|
194
|
-
|
|
195
|
-
|
|
249
|
+
let resolved = direct ?? baseValue ?? null;
|
|
250
|
+
|
|
251
|
+
if (!resolved) {
|
|
252
|
+
const authStoreResolved = await resolveAuthStoreJidByLid(lid);
|
|
253
|
+
if (authStoreResolved) {
|
|
254
|
+
resolved = authStoreResolved;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const directHasJid = typeof direct === 'string' && direct.length > 0;
|
|
259
|
+
const shouldSeed = Boolean(resolved && (!directHasJid || direct !== resolved));
|
|
260
|
+
setCacheEntry(lid, resolved, resolved ? CACHE_TTL_MS : NEGATIVE_TTL_MS, shouldSeed ? 0 : undefined);
|
|
261
|
+
if (shouldSeed) {
|
|
262
|
+
queueLidUpdate(lid, resolved, 'prime');
|
|
263
|
+
}
|
|
196
264
|
results.set(lid, resolved);
|
|
197
265
|
}
|
|
198
266
|
|
|
@@ -379,6 +447,15 @@ const fetchJidByLid = async (lid) => {
|
|
|
379
447
|
const direct = rowMap.has(lid) ? rowMap.get(lid) : undefined;
|
|
380
448
|
const baseValue = base && base !== lid && rowMap.has(base) ? rowMap.get(base) : undefined;
|
|
381
449
|
let resolved = direct ?? baseValue ?? null;
|
|
450
|
+
let resolveSource = 'db';
|
|
451
|
+
|
|
452
|
+
if (!resolved) {
|
|
453
|
+
const authStoreResolved = await resolveAuthStoreJidByLid(lid);
|
|
454
|
+
if (authStoreResolved) {
|
|
455
|
+
resolved = authStoreResolved;
|
|
456
|
+
resolveSource = 'auth-store';
|
|
457
|
+
}
|
|
458
|
+
}
|
|
382
459
|
|
|
383
460
|
if (!resolved) {
|
|
384
461
|
const normalized = base || lid;
|
|
@@ -404,16 +481,18 @@ const fetchJidByLid = async (lid) => {
|
|
|
404
481
|
const derivedJid = derivedRows?.[0]?.jid;
|
|
405
482
|
if (derivedJid && isWhatsAppJid(derivedJid)) {
|
|
406
483
|
resolved = normalizeJid(derivedJid);
|
|
484
|
+
resolveSource = 'derived';
|
|
407
485
|
}
|
|
408
486
|
}
|
|
409
487
|
}
|
|
410
488
|
|
|
411
|
-
const
|
|
489
|
+
const directHasJid = typeof direct === 'string' && direct.length > 0;
|
|
490
|
+
const shouldSeedDerived = Boolean(resolved && (!directHasJid || direct !== resolved));
|
|
412
491
|
|
|
413
492
|
setCacheEntry(lid, resolved, resolved ? CACHE_TTL_MS : NEGATIVE_TTL_MS, shouldSeedDerived ? 0 : undefined);
|
|
414
493
|
|
|
415
494
|
if (shouldSeedDerived) {
|
|
416
|
-
queueLidUpdate(lid, resolved, 'derived');
|
|
495
|
+
queueLidUpdate(lid, resolved, resolveSource === 'auth-store' ? 'auth-store' : 'derived');
|
|
417
496
|
}
|
|
418
497
|
|
|
419
498
|
return resolved;
|
package/package.json
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
<meta name="author" content="OmniZap System" />
|
|
10
10
|
<meta name="robots" content="index, follow, max-snippet:-1" />
|
|
11
11
|
<link rel="canonical" href="https://omnizap.shop/api-docs/" />
|
|
12
|
-
<link rel="icon"
|
|
13
|
-
<link rel="
|
|
12
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
13
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
14
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
14
15
|
<link rel="sitemap" type="application/xml" href="https://omnizap.shop/sitemap.xml" />
|
|
15
16
|
<meta property="og:type" content="website" />
|
|
16
17
|
<meta property="og:locale" content="pt_BR" />
|
|
Binary file
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
<meta name="keywords" content="bot para grupo whatsapp, bot whatsapp pronto, automacao para grupos, moderacao grupo whatsapp" />
|
|
9
9
|
<meta name="robots" content="index, follow" />
|
|
10
10
|
<link rel="canonical" href="https://omnizap.shop/bot-whatsapp-para-grupo/" />
|
|
11
|
-
<link rel="icon"
|
|
11
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
12
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
13
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
12
14
|
|
|
13
15
|
<meta property="og:type" content="article" />
|
|
14
16
|
<meta property="og:locale" content="pt_BR" />
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
<meta name="keywords" content="bot whatsapp sem programar, bot pronto whatsapp, automacao whatsapp sem codigo" />
|
|
9
9
|
<meta name="robots" content="index, follow" />
|
|
10
10
|
<link rel="canonical" href="https://omnizap.shop/bot-whatsapp-sem-programar/" />
|
|
11
|
-
<link rel="icon"
|
|
11
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
12
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
13
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
12
14
|
|
|
13
15
|
<meta property="og:type" content="article" />
|
|
14
16
|
<meta property="og:locale" content="pt_BR" />
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
<meta name="keywords" content="comandos bot whatsapp, comandos omnizap, bot para grupo whatsapp, automacao whatsapp" />
|
|
9
9
|
<meta name="robots" content="index, follow, max-snippet:-1" />
|
|
10
10
|
<link rel="canonical" href="https://omnizap.shop/comandos/" />
|
|
11
|
-
<link rel="icon"
|
|
12
|
-
<link rel="
|
|
11
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
12
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
13
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
13
14
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
14
15
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
15
16
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@600;700;800&display=swap" />
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
<meta name="keywords" content="automatizar avisos whatsapp, lembrete automatico whatsapp, bot para avisos" />
|
|
9
9
|
<meta name="robots" content="index, follow" />
|
|
10
10
|
<link rel="canonical" href="https://omnizap.shop/como-automatizar-avisos-no-whatsapp/" />
|
|
11
|
-
<link rel="icon"
|
|
11
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
12
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
13
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
12
14
|
|
|
13
15
|
<meta property="og:type" content="article" />
|
|
14
16
|
<meta property="og:locale" content="pt_BR" />
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
<meta name="keywords" content="comandos whatsapp, bot com comandos, automacao de respostas whatsapp" />
|
|
9
9
|
<meta name="robots" content="index, follow" />
|
|
10
10
|
<link rel="canonical" href="https://omnizap.shop/como-criar-comandos-whatsapp/" />
|
|
11
|
-
<link rel="icon"
|
|
11
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
12
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
13
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
12
14
|
|
|
13
15
|
<meta property="og:type" content="article" />
|
|
14
16
|
<meta property="og:locale" content="pt_BR" />
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
<meta name="keywords" content="como evitar spam whatsapp, bot anti spam whatsapp, moderacao whatsapp" />
|
|
9
9
|
<meta name="robots" content="index, follow" />
|
|
10
10
|
<link rel="canonical" href="https://omnizap.shop/como-evitar-spam-no-whatsapp/" />
|
|
11
|
-
<link rel="icon"
|
|
11
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
12
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
13
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
12
14
|
|
|
13
15
|
<meta property="og:type" content="article" />
|
|
14
16
|
<meta property="og:locale" content="pt_BR" />
|