Skip to content

Instantly share code, notes, and snippets.

@SoursopID
Last active February 2, 2025 12:52
Show Gist options
  • Save SoursopID/36c2165389b20b801f449d36832eb53f to your computer and use it in GitHub Desktop.
Save SoursopID/36c2165389b20b801f449d36832eb53f to your computer and use it in GitHub Desktop.
Detect bot by qoute ID, sender device ID and participant zero.
/*
* Copyright(C) 2025 SoursopID
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
*
* */
/* Cautions :
* This code may not work as expected if participant jid doesn't contain
* deviceID <number>:<deviceID>@s.whatsapp.net.
* You need to patch your Baileys library to include deviceID in jid
* or avoid normalize participant jid. Just needed to comment this line.
*
* Baileys/src/Utils/process-message.ts:37
* // message.key.participant = message.key.participant ? jidNormalizedUser(message.key.participant) : undefined
*
*
*
*
*
*
* Exampe usage:
* const { BotDetector } = require("./botdetector.js");
*
* const maxBotDelay = 3; // seconds
* const quarantine = true; // true or false
* const botDetect = new BotDetector(maxBotDelay, quarantine);
*
* client.ev.on("messages.upsert", async (chatUpdate, msg) => {
*
* if (botDetect.isBot(chatUpdate)) {
* // do something
* }
*
* ...
* })
* */
const ZERO_WHATSAPP_USER = '[email protected]';
const HEX_CHARS = '0123456789ABCDEF';
class BotDetector {
constructor(timeout, quarantine) {
this.timeout = timeout;
this.quarantine_jids = {};
this.ignore_jids = {};
this.activity_id = {};
this.quarantine = quarantine;
}
// jid = '<number>:<deviceID>'
addIgnore(jid) {
this.ignore_jids[jid] = Date.now();
}
deleteIgnore(jid) {
delete this.ignore_jids[jid];
}
isIgnored(jid) {
return this.ignore_jids[jid];
}
addQuarantine(jid) {
this.quarantine_jids[jid] = Date.now();
}
deleteQuarantine(jid) {
delete this.quarantine_jids[jid];
}
isQuarantined(jid) {
return this.quarantine_jids[jid];
}
addActivityID(activityID, timestamp) {
this.activity_id[activityID] = timestamp;
}
deleteActivityID(activityID) {
delete this.activity_id[activityID];
}
isMatchTime(quotedID, messageTimestamp) {
let data = this.activity_id[quotedID];
if ((messageTimestamp - data) <= this.timeout) {
return true;
} else {
this.deleteActivityID(quotedID);
}
return false;
}
realIsBot(senderParticipant, messageID, quotedID, participant, messageTimestamp) {
let senderSplitted = senderParticipant.split('@');
let senderDeviceID = senderSplitted[0]?.search(':') > -1 ? senderSplitted[0].split(':')[1] : 0;
let senderUser = senderSplitted[0]?.search(':') > -1 ? senderSplitted[0].split(':')[1] : 0;
let quarantineSender = `${senderUser}:${senderDeviceID}`;
let detected = false;
if (this.isQuarantined(quarantineSender)) {
detected = true;
}
if (messageID) {
messageID.split('').forEach((char) => {
char = char.toUpperCase();
if (!HEX_CHARS.includes(char)) {
detected = true
}
});
}
if ((senderDeviceID > 0) && !detected) {
if (this.isIgnored(quarantineSender)) {
detected = false;
}
if (participant === ZERO_WHATSAPP_USER) {
detected = true;
}
if (this.isMatchTime(quotedID, messageTimestamp)) {
detected = true;
}
if (detected && this.quarantine) {
this.addQuarantine(quarantineSender);
}
}
this.addActivityID(messageID, messageTimestamp);
return detected;
}
isBot(update) {
if (!update.messages) {
return false
}
const message = update.messages[0];
if (!message.message) { return false }
const senderParticipant = message.key.participant;
const messageID = message.key.id;
const timestamp = message.messageTimestamp;
let quotedID = "";
let participant = "";
let ctx;
const messagejson = JSON.parse(JSON.stringify(message.message));
Object.keys(messagejson).forEach((key) => {
ctx = messagejson[key].contextInfo ? messagejson[key].contextInfo : null;
if (key === "reactionMessage") {
quotedID = messagejson[key].key.id;
participant = messagejson[key].key.participant;
}
});
if (ctx) {
quotedID = ctx.stanzaId || "";
participant = ctx.participant || "";
}
// console.log(message.pushName, senderParticipant, messageID, quotedID, participant, timestamp);
return this.realIsBot(senderParticipant, messageID, quotedID, participant, timestamp);
}
}
module.exports = { BotDetector };
diff --git a/src/Utils/process-message.ts b/src/Utils/process-message.ts
index 133b0ff51..042416de3 100644
--- a/src/Utils/process-message.ts
+++ b/src/Utils/process-message.ts
@@ -34,7 +34,7 @@ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([
export const cleanMessage = (message: proto.IWebMessageInfo, meId: string) => {
// ensure remoteJid and participant doesn't have device or agent in it
message.key.remoteJid = jidNormalizedUser(message.key.remoteJid!)
- message.key.participant = message.key.participant ? jidNormalizedUser(message.key.participant) : undefined
+ // message.key.participant = message.key.participant ? jidNormalizedUser(message.key.participant) : undefined
const content = normalizeMessageContent(message.message)
// if the message has a reaction, ensure fromMe & remoteJid are from our perspective
if(content?.reactionMessage) {
@mhdramd
Copy link

mhdramd commented Oct 25, 2024

Nice

@SoursopID
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment