From f94a99ae399bf83bdfe6b48b70bd8e78311fcfb9 Mon Sep 17 00:00:00 2001 From: konsisumer Date: Wed, 10 Jun 2026 18:59:45 +0200 Subject: [PATCH] fix(whatsapp): honor proxy env vars during pairing --- scripts/whatsapp-bridge/bridge.js | 2 + scripts/whatsapp-bridge/package-lock.json | 46 +++++++++++++++++++++++ scripts/whatsapp-bridge/package.json | 1 + scripts/whatsapp-bridge/proxy.js | 38 +++++++++++++++++++ scripts/whatsapp-bridge/proxy.test.mjs | 43 +++++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 scripts/whatsapp-bridge/proxy.js create mode 100644 scripts/whatsapp-bridge/proxy.test.mjs diff --git a/scripts/whatsapp-bridge/bridge.js b/scripts/whatsapp-bridge/bridge.js index 5723d8b543b8..479259d653a2 100644 --- a/scripts/whatsapp-bridge/bridge.js +++ b/scripts/whatsapp-bridge/bridge.js @@ -29,6 +29,7 @@ import { execSync } from 'child_process'; import { tmpdir } from 'os'; import qrcode from 'qrcode-terminal'; import { matchesAllowedUser, parseAllowedUsers } from './allowlist.js'; +import { buildSocketProxyOptions } from './proxy.js'; // Parse CLI args const args = process.argv.slice(2); @@ -196,6 +197,7 @@ async function startSocket() { // This is enough for Baileys to complete the retry handshake. return { conversation: '' }; }, + ...buildSocketProxyOptions(), }); sock.ev.on('creds.update', () => { saveCreds(); lidToPhone = buildLidMap(); }); diff --git a/scripts/whatsapp-bridge/package-lock.json b/scripts/whatsapp-bridge/package-lock.json index b662982cf5a3..b81381114753 100644 --- a/scripts/whatsapp-bridge/package-lock.json +++ b/scripts/whatsapp-bridge/package-lock.json @@ -10,10 +10,20 @@ "dependencies": { "@whiskeysockets/baileys": "WhiskeySockets/Baileys#01047debd81beb20da7b7779b08edcb06aa03770", "express": "^4.21.0", + "https-proxy-agent": "^7.0.6", "pino": "^9.0.0", "qrcode-terminal": "^0.12.0" } }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/@borewit/text-codec": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", @@ -1271,6 +1281,42 @@ "url": "https://opencollective.com/express" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2A4b5LY/NcI8h1wrt1AAJ2dZAX3T6iV3Czso4H16/7FlM30jCikmJp5mJDjT1mB5W6W0zN9bVQ==", + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/scripts/whatsapp-bridge/package.json b/scripts/whatsapp-bridge/package.json index d1c3ac113a0a..c31a350f4fc9 100644 --- a/scripts/whatsapp-bridge/package.json +++ b/scripts/whatsapp-bridge/package.json @@ -10,6 +10,7 @@ "dependencies": { "@whiskeysockets/baileys": "WhiskeySockets/Baileys#01047debd81beb20da7b7779b08edcb06aa03770", "express": "^4.21.0", + "https-proxy-agent": "^7.0.6", "qrcode-terminal": "^0.12.0", "pino": "^9.0.0" }, diff --git a/scripts/whatsapp-bridge/proxy.js b/scripts/whatsapp-bridge/proxy.js new file mode 100644 index 000000000000..6bfe5f444e60 --- /dev/null +++ b/scripts/whatsapp-bridge/proxy.js @@ -0,0 +1,38 @@ +import { createRequire } from 'node:module'; + +const require = createRequire(import.meta.url); + +const PROXY_ENV_KEYS = [ + 'HTTPS_PROXY', + 'https_proxy', + 'HTTP_PROXY', + 'http_proxy', +]; + +export function resolveProxyUrl(env = process.env) { + for (const key of PROXY_ENV_KEYS) { + const value = env?.[key]; + if (typeof value === 'string' && value.trim()) { + return value.trim(); + } + } + return ''; +} + +function loadHttpsProxyAgent() { + return require('https-proxy-agent').HttpsProxyAgent; +} + +export function createProxyAgent(env = process.env, ProxyAgentCtor = undefined) { + const proxyUrl = resolveProxyUrl(env); + if (!proxyUrl) { + return undefined; + } + const AgentCtor = ProxyAgentCtor || loadHttpsProxyAgent(); + return new AgentCtor(proxyUrl); +} + +export function buildSocketProxyOptions(env = process.env, ProxyAgentCtor = undefined) { + const agent = createProxyAgent(env, ProxyAgentCtor); + return agent ? { agent } : {}; +} diff --git a/scripts/whatsapp-bridge/proxy.test.mjs b/scripts/whatsapp-bridge/proxy.test.mjs new file mode 100644 index 000000000000..41ac385375ba --- /dev/null +++ b/scripts/whatsapp-bridge/proxy.test.mjs @@ -0,0 +1,43 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; + +import { buildSocketProxyOptions, createProxyAgent, resolveProxyUrl } from './proxy.js'; + +class FakeProxyAgent { + constructor(proxyUrl) { + this.proxyUrl = proxyUrl; + } +} + +test('resolveProxyUrl prefers HTTPS proxy variables first', () => { + const env = { + HTTP_PROXY: 'http://http-proxy.example:8080', + HTTPS_PROXY: 'http://https-proxy.example:8443', + }; + + assert.equal(resolveProxyUrl(env), 'http://https-proxy.example:8443'); +}); + +test('resolveProxyUrl falls back across lowercase and HTTP variants', () => { + assert.equal( + resolveProxyUrl({ http_proxy: 'http://lower-http.example:8080' }), + 'http://lower-http.example:8080', + ); + assert.equal( + resolveProxyUrl({ HTTP_PROXY: 'http://upper-http.example:8080' }), + 'http://upper-http.example:8080', + ); + assert.equal(resolveProxyUrl({ HTTPS_PROXY: ' ' }), ''); +}); + +test('createProxyAgent returns undefined when no proxy is configured', () => { + assert.equal(createProxyAgent({}), undefined); +}); + +test('buildSocketProxyOptions wires an HttpsProxyAgent for Baileys', () => { + const proxyUrl = 'http://proxy.example:3128'; + const options = buildSocketProxyOptions({ HTTPS_PROXY: proxyUrl }, FakeProxyAgent); + + assert.ok(options.agent instanceof FakeProxyAgent); + assert.equal(options.agent.proxyUrl, proxyUrl); +});