feat: WhatsApp-Webhook mit Signatur-Prüfung und Queue-Enqueue

This commit is contained in:
Hermes Agent
2026-06-22 06:37:34 +02:00
parent 5a72f9ec80
commit a6d3dc2189
2 changed files with 142 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
"""Tests für den WhatsApp-Webhook-Blueprint."""
from __future__ import annotations
import hashlib
import hmac
import os
import fakeredis
import pytest
from flask.testing import FlaskClient
from src.app import create_app
from src.queue.handler import QueueHandler
from src.routes.whatsapp import whatsapp_bp
os.environ["WHATSAPP_APP_SECRET"] = "test" # noqa: S105
os.environ["WHATSAPP_VERIFY_TOKEN"] = "test-token" # noqa: S105
SECRET = "test" # noqa: S105
PAYLOAD = b'{"message_id": "123", "absender": "+491234", "text": "Hallo"}'
EXPECTED_HMAC = hmac.new(SECRET.encode(), PAYLOAD, hashlib.sha256).hexdigest()
VALID_SIGNATURE = f"sha256={EXPECTED_HMAC}"
@pytest.fixture
def client() -> FlaskClient:
"""Test-Client mit fakeredis und registriertem whatsapp-Blueprint."""
app = create_app()
# QueueHandler mit fakeredis ersetzen
fake_redis = fakeredis.FakeRedis(decode_responses=True)
qh = QueueHandler.__new__(QueueHandler)
qh.redis = fake_redis
qh.stream_key = "bsn:submissions"
qh.processed_set = "bsn:processed"
qh.stream_ids_hash = "bsn:stream_ids"
qh.group_name = "bsn-workers"
qh._ensure_consumer_group()
app.queue_handler = qh # type: ignore[attr-defined]
app.register_blueprint(whatsapp_bp)
return app.test_client()
class TestWhatsAppWebhookGET:
"""Tests für GET /webhook/whatsapp (Hub-Challenge)."""
def test_correct_verify_token_returns_challenge(self, client: FlaskClient) -> None:
"""GET mit korrektem verify_token → 200 + Challenge."""
response = client.get(
"/webhook/whatsapp",
query_string={
"hub.mode": "subscribe",
"hub.verify_token": "test-token",
"hub.challenge": "abc123",
},
)
assert response.status_code == 200
assert response.get_data(as_text=True) == "abc123"
def test_wrong_verify_token_returns_403(self, client: FlaskClient) -> None:
"""GET mit falschem verify_token → 403."""
response = client.get(
"/webhook/whatsapp",
query_string={
"hub.mode": "subscribe",
"hub.verify_token": "wrong-token",
"hub.challenge": "abc123",
},
)
assert response.status_code == 403
class TestWhatsAppWebhookPOST:
"""Tests für POST /webhook/whatsapp (Nachrichtenempfang)."""
def test_correct_signature_returns_200(self, client: FlaskClient) -> None:
"""POST mit korrekter Signatur → 200."""
response = client.post(
"/webhook/whatsapp",
data=PAYLOAD,
content_type="application/json",
headers={"X-Hub-Signature-256": VALID_SIGNATURE},
)
assert response.status_code == 200
def test_wrong_signature_returns_401(self, client: FlaskClient) -> None:
"""POST mit falscher Signatur → 401."""
response = client.post(
"/webhook/whatsapp",
data=PAYLOAD,
content_type="application/json",
headers={"X-Hub-Signature-256": "sha256=wrongsignature"},
)
assert response.status_code == 401