Files

63 lines
2.0 KiB
Python

from __future__ import annotations
import pytest
from app.security import (
WebhookValidationError,
parse_bounded_form,
redact,
token_matches,
validate_webhook,
)
def test_contact_webhook_contract(full_settings) -> None:
event = validate_webhook(
"contact",
{"token": "contact-token-value-32-characters", "ID": "42"},
{
"document_id[0]": "crm",
"document_id[1]": "CCrmDocumentContact",
"document_id[2]": "CONTACT_42",
"auth[domain]": "portal.example",
"auth[member_id]": "member_12345678",
"auth[client_endpoint]": "https://attacker.invalid/rest/",
},
"203.0.113.10",
full_settings,
alert_entity_type_id=None,
)
assert event.entity_id == "42"
def test_webhook_rejects_document_query_mismatch(full_settings) -> None:
with pytest.raises(WebhookValidationError, match="mismatch"):
validate_webhook(
"contact",
{"token": "contact-token-value-32-characters", "ID": "41"},
{
"document_id[0]": "crm",
"document_id[1]": "CCrmDocumentContact",
"document_id[2]": "CONTACT_42",
"auth[domain]": "portal.example",
"auth[member_id]": "member_12345678",
},
"203.0.113.10",
full_settings,
alert_entity_type_id=None,
)
def test_bounded_form_and_constant_time_token_helpers() -> None:
assert parse_bounded_form(b"a=1&b=2", max_fields=2) == {"a": "1", "b": "2"}
with pytest.raises(WebhookValidationError):
parse_bounded_form(b"a=1&b=2&c=3", max_fields=2)
assert token_matches("old", "new", "old")
assert not token_matches("other", "new", "old")
def test_redaction_removes_pii_and_secrets() -> None:
assert "secret-value" not in redact("token=secret-value")
assert redact("user@example.test") == "[PII_REDACTED]"
assert redact("+79001234567") == "[PII_REDACTED]"