63 lines
2.0 KiB
Python
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]"
|