Files
notify-bridge/packages/server/tests/test_email_client.py
T
alexei.dolgolyov 0eb899afb9 feat: harden notification stack and switch logging selectors to icon grid
Notifications:
- Add shared http_base, redact, and SSRF hardening modules
- Refactor dispatcher, queue, receiver and per-provider clients
  (telegram, discord, email, matrix, ntfy, slack, webhook) to use
  the shared base, with bounded queue and redacted error logs
- Tests for ssrf, redact, http_base, queue bounds, dispatcher
  aggregation, telegram media partition, email and matrix clients

Frontend:
- Settings: log level / log format selectors now use IconGridSelect
  with per-option icons and i18n descriptions
- Minor providers page and entity-cache store updates

Tooling:
- Document code-review-graph MCP usage in CLAUDE.md
- Ignore .code-review-graph/, register .mcp.json
2026-05-07 13:53:26 +03:00

78 lines
2.2 KiB
Python

"""Email client header-injection / address-validation regression tests."""
from __future__ import annotations
import pytest
from notify_bridge_core.notifications.email.client import (
EmailClient,
SmtpConfig,
_strip_header,
_validate_email,
_to_html,
)
def test_strip_header_removes_crlf() -> None:
out = _strip_header("Subject\r\nBcc: attacker@example.com")
assert "\r" not in out
assert "\n" not in out
# The injected "Bcc:" line is folded to a single header line; the SMTP
# server will treat it as part of the subject text, not a header.
assert "Bcc:" in out # value preserved as plain text
def test_strip_header_removes_bare_lf() -> None:
out = _strip_header("Hello\nWorld")
assert "\n" not in out
def test_strip_header_handles_non_string() -> None:
assert _strip_header(None) == ""
def test_validate_email_rejects_crlf() -> None:
with pytest.raises(ValueError):
_validate_email("user@example.com\r\nBcc: x@y")
def test_validate_email_rejects_no_at() -> None:
with pytest.raises(ValueError):
_validate_email("not-an-email")
def test_validate_email_rejects_empty() -> None:
with pytest.raises(ValueError):
_validate_email("")
def test_validate_email_accepts_normal() -> None:
assert _validate_email("user@example.com") == "user@example.com"
def test_to_html_escapes_brackets() -> None:
out = _to_html("<script>alert(1)</script>")
assert "<script>" not in out
assert "&lt;script&gt;" in out
@pytest.mark.asyncio
async def test_send_returns_error_on_invalid_to() -> None:
cfg = SmtpConfig(host="smtp.example.com", from_address="from@example.com")
client = EmailClient(cfg)
result = await client.send(
to_email="user@example.com\r\nBcc: attacker@example.com",
subject="hi",
body_text="body",
)
assert result["success"] is False
assert "Invalid email" in result["error"]
@pytest.mark.asyncio
async def test_send_returns_error_on_no_host() -> None:
cfg = SmtpConfig(host="", from_address="from@example.com")
client = EmailClient(cfg)
result = await client.send("u@x.com", "s", "b")
assert result["success"] is False