Fix fetchLatestWaWebVersion to bypass WhatsApp anti-bot detection with minimal headers (#1883)

* fix: fetchLatestWaWebVersion to curl

* fix: lint

* fix: fetchLatestWaWebVersion to bypass WhatsApp anti-bot detection with minimal headers

---------

Co-authored-by: João Lucas <jlucaso@hotmail.com>
This commit is contained in:
Gustavo Quadri
2025-10-07 14:06:45 -03:00
committed by GitHub
parent 9a8f19461c
commit 60c688b85d
4 changed files with 74 additions and 3 deletions
+1
View File
@@ -66,6 +66,7 @@ export const makeGroupsSocket = (config: SocketConfig) => {
data[meta.id] = meta
}
}
// TODO: properly parse LID / PN DATA
sock.ev.emit('groups.update', Object.values(data))
+1 -1
View File
@@ -699,7 +699,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
for (const device of devices) {
const deviceJid = device.jid
const hasKey = !!senderKeyMap[deviceJid]
if ((!hasKey || !!participant ) && !isJidHostedLidUser(deviceJid) && !isJidHostedPnUser(deviceJid)) {
if ((!hasKey || !!participant) && !isJidHostedLidUser(deviceJid) && !isJidHostedPnUser(deviceJid)) {
//todo: revamp all this logic
// the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
senderKeyRecipients.push(deviceJid)
+12 -2
View File
@@ -274,11 +274,21 @@ export const fetchLatestBaileysVersion = async (options: RequestInit = {}) => {
*/
export const fetchLatestWaWebVersion = async (options: RequestInit = {}) => {
try {
// Absolute minimal headers required to bypass anti-bot detection
const defaultHeaders = {
'sec-fetch-site': 'none',
'user-agent':
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
}
const headers = { ...defaultHeaders, ...options.headers }
const response = await fetch('https://web.whatsapp.com/sw.js', {
dispatcher: options.dispatcher,
...options,
method: 'GET',
headers: options.headers
headers
})
if (!response.ok) {
throw new Boom(`Failed to fetch sw.js: ${response.statusText}`, { statusCode: response.status })
}
@@ -0,0 +1,60 @@
import { jest } from '@jest/globals'
import { fetchLatestWaWebVersion } from '../../Utils/generics'
describe('fetchLatestWaWebVersion Integration Tests', () => {
jest.setTimeout(10000)
it('should successfully fetch the latest WhatsApp Web version from real API', async () => {
const result = await fetchLatestWaWebVersion()
expect(Array.isArray(result.version)).toBe(true)
expect(result.version).toHaveLength(3)
expect(typeof result.version[0]).toBe('number')
expect(typeof result.version[1]).toBe('number')
expect(typeof result.version[2]).toBe('number')
expect(typeof result.isLatest).toBe('boolean')
if (!result.isLatest) {
expect(result.error).toBeDefined()
}
})
it('should handle custom headers correctly', async () => {
const customHeaders = {
accept:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'accept-language': 'en-US,en;q=0.9',
'cache-control': 'max-age=0',
'sec-ch-prefers-color-scheme': 'dark',
'sec-fetch-dest': 'document',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'upgrade-insecure-requests': '1'
}
const result = await fetchLatestWaWebVersion({
headers: customHeaders
})
expect(Array.isArray(result.version)).toBe(true)
expect(result.version).toHaveLength(3)
expect(result.isLatest).toBe(true)
})
it('should fallback gracefully when client_revision is not found', async () => {
const result = await fetchLatestWaWebVersion()
expect(result).toHaveProperty('version')
expect(result).toHaveProperty('isLatest')
expect(Array.isArray(result.version)).toBe(true)
})
it('should handle network timeouts gracefully', async () => {
const result = await fetchLatestWaWebVersion()
expect(result).toHaveProperty('version')
expect(result).toHaveProperty('isLatest')
expect(Array.isArray(result.version)).toBe(true)
})
})