mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-04-28 03:30:23 +00:00
fix: move allowed_numbers filtering from JS bridge to Python handler
The JS bridge used LIDs (internal WhatsApp identifiers) for sender matching which never matched actual phone numbers. Moved filtering to Python handler.py where config is read fresh each poll cycle. - Add senderNumber (resolved phone) to bridge message payload - Filter in poll_messages() with normalized number comparison - Remove --allowed-numbers CLI arg and JS-side filtering - Fix ensure_bridge_http_up not recording _bridge_config - Fix falsy empty-dict check in bridge restart detection
This commit is contained in:
parent
64ee177897
commit
61fa1bf487
6 changed files with 37 additions and 31 deletions
|
|
@ -15,7 +15,6 @@ class QrCode(ApiHandler):
|
|||
port = int(config.get("bridge_port", 3100))
|
||||
session_dir = files.get_abs_path("usr/whatsapp/sessions")
|
||||
cache_dir = files.get_abs_path("usr/whatsapp/media")
|
||||
allowed_numbers = config.get("allowed_numbers") or []
|
||||
mode = config.get("mode", "dedicated")
|
||||
|
||||
from plugins._whatsapp_integration.helpers.bridge_manager import (
|
||||
|
|
@ -31,7 +30,7 @@ class QrCode(ApiHandler):
|
|||
if not is_process_alive():
|
||||
try:
|
||||
ok = await ensure_bridge_http_up(
|
||||
port, session_dir, cache_dir, allowed_numbers, mode=mode,
|
||||
port, session_dir, cache_dir, mode=mode,
|
||||
)
|
||||
if not ok:
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ class Start(ApiHandler):
|
|||
port = int(config.get("bridge_port", 3100))
|
||||
session_dir = files.get_abs_path("usr/whatsapp/sessions")
|
||||
cache_dir = files.get_abs_path("usr/whatsapp/media")
|
||||
allowed_numbers = config.get("allowed_numbers") or []
|
||||
mode = config.get("mode", "dedicated")
|
||||
|
||||
from plugins._whatsapp_integration.helpers.bridge_manager import (
|
||||
|
|
@ -28,7 +27,7 @@ class Start(ApiHandler):
|
|||
|
||||
try:
|
||||
ok = await ensure_bridge_http_up(
|
||||
port, session_dir, cache_dir, allowed_numbers, mode=mode,
|
||||
port, session_dir, cache_dir, mode=mode,
|
||||
)
|
||||
if ok:
|
||||
return {"success": True, "message": "Bridge started"}
|
||||
|
|
|
|||
|
|
@ -57,13 +57,12 @@ async def _poll_loop() -> None:
|
|||
port = int(config.get("bridge_port", 3100))
|
||||
session_dir = files.get_abs_path("usr/whatsapp/sessions")
|
||||
cache_dir = files.get_abs_path("usr/whatsapp/media")
|
||||
allowed_numbers = config.get("allowed_numbers") or []
|
||||
mode = config.get("mode", "dedicated")
|
||||
|
||||
# Detect config changes that require bridge restart
|
||||
desired = {"port": port, "mode": mode, "allowed_numbers": sorted(allowed_numbers)}
|
||||
desired = {"port": port, "mode": mode}
|
||||
running = bridge_manager.get_running_config()
|
||||
if bridge_started and bridge_manager.is_process_alive() and running and running != desired:
|
||||
if bridge_started and bridge_manager.is_process_alive() and running != desired:
|
||||
PrintStyle.info(f"WhatsApp: config changed, restarting bridge")
|
||||
await bridge_manager.stop_bridge()
|
||||
bridge_started = False
|
||||
|
|
@ -72,7 +71,7 @@ async def _poll_loop() -> None:
|
|||
if not bridge_started or not bridge_manager.is_process_alive():
|
||||
try:
|
||||
bridge_started = await bridge_manager.start_bridge(
|
||||
port, session_dir, cache_dir, allowed_numbers, mode=mode,
|
||||
port, session_dir, cache_dir, mode=mode,
|
||||
)
|
||||
except Exception as e:
|
||||
PrintStyle.error(f"WhatsApp bridge start error: {format_error(e)}")
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ async def start_bridge(
|
|||
port: int,
|
||||
session_dir: str,
|
||||
cache_dir: str,
|
||||
allowed_numbers: list[str] | None = None,
|
||||
mode: str = "dedicated",
|
||||
) -> bool:
|
||||
global _bridge_process
|
||||
|
|
@ -91,8 +90,6 @@ async def start_bridge(
|
|||
"--cache-dir", cache_dir,
|
||||
"--mode", mode,
|
||||
]
|
||||
if allowed_numbers:
|
||||
cmd += ["--allowed-numbers", ",".join(allowed_numbers)]
|
||||
|
||||
_kill_port_process(port)
|
||||
PrintStyle.info("WhatsApp: starting bridge")
|
||||
|
|
@ -104,7 +101,7 @@ async def start_bridge(
|
|||
), port)
|
||||
_start_log_reader(_bridge_process)
|
||||
_bridge_config.clear()
|
||||
_bridge_config.update({"port": port, "mode": mode, "allowed_numbers": sorted(allowed_numbers or [])})
|
||||
_bridge_config.update({"port": port, "mode": mode})
|
||||
|
||||
# Wait for bridge to become healthy
|
||||
for _ in range(20):
|
||||
|
|
@ -151,7 +148,6 @@ async def ensure_bridge_http_up(
|
|||
port: int,
|
||||
session_dir: str,
|
||||
cache_dir: str,
|
||||
allowed_numbers: list[str] | None = None,
|
||||
mode: str = "dedicated",
|
||||
) -> bool:
|
||||
"""Start bridge if needed and wait for HTTP server only (not WA connection)."""
|
||||
|
|
@ -170,8 +166,6 @@ async def ensure_bridge_http_up(
|
|||
"--cache-dir", cache_dir,
|
||||
"--mode", mode,
|
||||
]
|
||||
if allowed_numbers:
|
||||
cmd += ["--allowed-numbers", ",".join(allowed_numbers)]
|
||||
|
||||
_kill_port_process(port)
|
||||
PrintStyle.info("WhatsApp: starting bridge for pairing")
|
||||
|
|
@ -182,6 +176,8 @@ async def ensure_bridge_http_up(
|
|||
cwd=BRIDGE_DIR,
|
||||
), port)
|
||||
_start_log_reader(_bridge_process)
|
||||
_bridge_config.clear()
|
||||
_bridge_config.update({"port": port, "mode": mode})
|
||||
|
||||
for _ in range(20):
|
||||
await asyncio.sleep(0.5)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,17 @@ from plugins._whatsapp_integration.helpers import bridge_manager
|
|||
PLUGIN_NAME = "_whatsapp_integration"
|
||||
MEDIA_FOLDER = "usr/whatsapp/media"
|
||||
|
||||
# Regex: strip everything from first '@' or ':' onward, then leading '+' and '0's
|
||||
_NUM_STRIP_RE = re.compile(r"[@:].*")
|
||||
_NUM_PREFIX_RE = re.compile(r"^[+0]+")
|
||||
|
||||
|
||||
def _normalize_number(raw: str) -> str:
|
||||
"""Strip JID suffix, device suffix, leading + and 0s to get a plain number."""
|
||||
n = _NUM_STRIP_RE.sub("", raw)
|
||||
n = _NUM_PREFIX_RE.sub("", n)
|
||||
return n
|
||||
|
||||
# Context data keys (no underscore prefix — must persist across restarts)
|
||||
CTX_WA_CHAT_ID = "wa_chat_id"
|
||||
CTX_WA_SENDER_NAME = "wa_sender_name"
|
||||
|
|
@ -80,8 +91,21 @@ async def poll_messages(config: dict) -> None:
|
|||
if not messages:
|
||||
return
|
||||
|
||||
# Allowed-numbers filtering (authoritative check — bridge.js is secondary)
|
||||
allowed_numbers = config.get("allowed_numbers") or []
|
||||
allowed_set = {_normalize_number(n) for n in allowed_numbers} if allowed_numbers else set()
|
||||
|
||||
for msg in messages:
|
||||
try:
|
||||
# Filter by allowed numbers if configured
|
||||
if allowed_set:
|
||||
sender_num = _normalize_number(msg.get("senderNumber", "") or msg.get("senderId", ""))
|
||||
if sender_num not in allowed_set:
|
||||
PrintStyle.debug(
|
||||
f"WhatsApp: ignored message from {sender_num} "
|
||||
f"(senderId: {msg.get('senderId', '')}, allowed: {allowed_set})"
|
||||
)
|
||||
continue
|
||||
await _dispatch_message(config, msg)
|
||||
except Exception as e:
|
||||
PrintStyle.error(f"WhatsApp dispatch error: {format_error(e)}")
|
||||
|
|
@ -126,7 +150,7 @@ async def _start_new_chat(config: dict, msg: dict) -> None:
|
|||
from helpers import projects
|
||||
|
||||
sender_name = msg.get("senderName", "Unknown")
|
||||
sender_number = msg.get("senderId", "").replace("@s.whatsapp.net", "").replace("@lid", "")
|
||||
sender_number = msg.get("senderNumber", "") or _normalize_number(msg.get("senderId", ""))
|
||||
chat_id = msg.get("chatId", "")
|
||||
is_group = msg.get("isGroup", False)
|
||||
|
||||
|
|
@ -260,7 +284,7 @@ def _md_to_whatsapp(text: str) -> str:
|
|||
|
||||
def _build_user_message(agent: Agent, msg: dict) -> str:
|
||||
sender_name = msg.get("senderName", "Unknown")
|
||||
sender_number = msg.get("senderId", "").replace("@s.whatsapp.net", "").replace("@lid", "")
|
||||
sender_number = msg.get("senderNumber", "") or _normalize_number(msg.get("senderId", ""))
|
||||
is_group = msg.get("isGroup", False)
|
||||
prompt = "fw.wa.user_message_group.md" if is_group else "fw.wa.user_message.md"
|
||||
text = agent.read_prompt(
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const SESSION_DIR = getArg('session', path.join(process.env.HOME || '~', '.agent
|
|||
const CACHE_DIR = getArg('cache-dir', path.join(process.env.HOME || '~', '.agent-zero', 'whatsapp', 'media'));
|
||||
const PAIR_ONLY = args.includes('--pair-only');
|
||||
const MODE = getArg('mode', 'dedicated'); // "dedicated" or "self-chat"
|
||||
const ALLOWED_NUMBERS = (getArg('allowed-numbers', '') || '').split(',').map(s => s.trim()).filter(Boolean);
|
||||
|
||||
|
||||
mkdirSync(SESSION_DIR, { recursive: true });
|
||||
mkdirSync(CACHE_DIR, { recursive: true });
|
||||
|
|
@ -197,14 +197,7 @@ async function startSocket() {
|
|||
// Skip status broadcasts
|
||||
if (chatId === 'status@broadcast') continue;
|
||||
|
||||
// Check allowlist (resolve LID -> phone if needed)
|
||||
if (!msg.key.fromMe && ALLOWED_NUMBERS.length > 0) {
|
||||
const resolvedNumber = lidToPhone[senderNumber] || senderNumber;
|
||||
if (!ALLOWED_NUMBERS.includes(resolvedNumber)) {
|
||||
console.log(`[bridge] Ignored message from ${resolvedNumber} (not in allowed numbers)`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Allowed-numbers filtering is handled in Python (handler.py)
|
||||
|
||||
// Unwrap documentWithCaptionMessage (Baileys wraps captioned docs)
|
||||
if (msg.message.documentWithCaptionMessage?.message?.documentMessage) {
|
||||
|
|
@ -379,6 +372,7 @@ async function startSocket() {
|
|||
messageId: msg.key.id,
|
||||
chatId,
|
||||
senderId,
|
||||
senderNumber: resolvedSender,
|
||||
senderName: msg.pushName || resolvedSender,
|
||||
chatName,
|
||||
isGroup,
|
||||
|
|
@ -616,11 +610,6 @@ if (PAIR_ONLY) {
|
|||
app.listen(PORT, '127.0.0.1', () => {
|
||||
console.log(`[bridge] WhatsApp bridge listening on port ${PORT} (mode: ${MODE})`);
|
||||
console.log(`[bridge] Session: ${SESSION_DIR}`);
|
||||
if (ALLOWED_NUMBERS.length > 0) {
|
||||
console.log(`[bridge] Allowed numbers: ${ALLOWED_NUMBERS.join(', ')}`);
|
||||
} else {
|
||||
console.log('[bridge] No allowed numbers set — all messages will be processed');
|
||||
}
|
||||
console.log();
|
||||
startSocket();
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue