system-prompts-and-models-o.../dealix/tests/test_whatsapp_signature.py
2026-05-01 14:03:52 +03:00

76 lines
2.5 KiB
Python

"""Meta WhatsApp X-Hub-Signature-256 and webhook safety helpers."""
from __future__ import annotations
import hashlib
import hmac
import pytest
from httpx import ASGITransport, AsyncClient
from api.main import create_app
from core.config.settings import get_settings
from integrations.whatsapp import WhatsAppClient
@pytest.fixture(autouse=True)
def _reset_settings_cache():
get_settings.cache_clear()
yield
get_settings.cache_clear()
def _meta_sig(body: bytes, app_secret: str) -> str:
digest = hmac.new(app_secret.encode(), body, hashlib.sha256).hexdigest()
return f"sha256={digest}"
def test_verify_signature_accepts_valid_header(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("WHATSAPP_APP_SECRET", "unit-test-secret")
app_secret = "unit-test-secret"
body = b'{"entry":[{"changes":[]}]}'
client = WhatsAppClient()
sig = _meta_sig(body, app_secret)
assert client.verify_signature(body, sig) is True
def test_verify_signature_rejects_tampered_body(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("WHATSAPP_APP_SECRET", "unit-test-secret")
get_settings.cache_clear()
client = WhatsAppClient()
sig = _meta_sig(b"original", "unit-test-secret")
assert client.verify_signature(b"tampered", sig) is False
@pytest.mark.asyncio
async def test_whatsapp_webhook_rejects_missing_signature_on_staging(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("APP_ENV", "staging")
monkeypatch.setenv("WHATSAPP_APP_SECRET", "staging-webhook-secret")
get_settings.cache_clear()
app = create_app()
try:
payload = {"entry": []}
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
r = await client.post("/api/v1/webhooks/whatsapp", json=payload)
assert r.status_code == 403
assert r.json().get("detail") == "missing_or_invalid_signature"
finally:
get_settings.cache_clear()
@pytest.mark.asyncio
async def test_whatsapp_meta_send_blocked_when_flag_off(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("WHATSAPP_ALLOW_LIVE_SEND", "false")
monkeypatch.setenv("WHATSAPP_ACCESS_TOKEN", "dummy-token")
monkeypatch.setenv("WHATSAPP_PHONE_NUMBER_ID", "123456")
get_settings.cache_clear()
try:
client = WhatsAppClient()
result = await client.send_text("+966500000001", "hello")
assert result.success is False
assert result.error == "whatsapp_allow_live_send_false"
finally:
get_settings.cache_clear()