# ABOUTME: Tests for CSRF validation logic. # ABOUTME: Covers token generation, token matching, origin/referer validation, and safe methods. class TestGenerateCSRFToken: """Tests for CSRF token generation.""" def test_generates_token_with_nonce_and_signature(self): """Token format is nonce:signature.""" from animaltrack.web.middleware import generate_csrf_token token = generate_csrf_token("test-secret") parts = token.split(":") assert len(parts) == 2 # Nonce is 32 hex chars (16 bytes) assert len(parts[0]) == 32 # Signature is 64 hex chars (SHA256) assert len(parts[1]) == 64 def test_generates_unique_tokens(self): """Each call generates a different token (random nonce).""" from animaltrack.web.middleware import generate_csrf_token token1 = generate_csrf_token("test-secret") token2 = generate_csrf_token("test-secret") assert token1 != token2 def test_tokens_are_hex_encoded(self): """Token parts are valid hex strings.""" from animaltrack.web.middleware import generate_csrf_token token = generate_csrf_token("test-secret") nonce, signature = token.split(":") # These should not raise ValueError int(nonce, 16) int(signature, 16) class TestValidateCSRFToken: """Tests for CSRF token validation logic.""" def test_accepts_matching_tokens(self): """Valid when cookie and header tokens match.""" from animaltrack.web.middleware import validate_csrf_token assert validate_csrf_token("abc123", "abc123") is True def test_rejects_mismatched_tokens(self): """Invalid when cookie and header tokens differ.""" from animaltrack.web.middleware import validate_csrf_token assert validate_csrf_token("abc123", "xyz789") is False def test_rejects_empty_cookie_token(self): """Invalid when cookie token is empty.""" from animaltrack.web.middleware import validate_csrf_token assert validate_csrf_token("", "abc123") is False def test_rejects_empty_header_token(self): """Invalid when header token is empty.""" from animaltrack.web.middleware import validate_csrf_token assert validate_csrf_token("abc123", "") is False def test_rejects_none_tokens(self): """Invalid when either token is None.""" from animaltrack.web.middleware import validate_csrf_token assert validate_csrf_token(None, "abc123") is False assert validate_csrf_token("abc123", None) is False assert validate_csrf_token(None, None) is False class TestIsSafeMethod: """Tests for HTTP safe method detection.""" def test_get_is_safe(self): """GET is a safe method.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("GET") is True def test_head_is_safe(self): """HEAD is a safe method.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("HEAD") is True def test_options_is_safe(self): """OPTIONS is a safe method.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("OPTIONS") is True def test_post_is_not_safe(self): """POST is not a safe method.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("POST") is False def test_put_is_not_safe(self): """PUT is not a safe method.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("PUT") is False def test_delete_is_not_safe(self): """DELETE is not a safe method.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("DELETE") is False def test_patch_is_not_safe(self): """PATCH is not a safe method.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("PATCH") is False def test_case_insensitive(self): """Method check is case-insensitive.""" from animaltrack.web.middleware import is_safe_method assert is_safe_method("get") is True assert is_safe_method("Get") is True assert is_safe_method("post") is False class TestValidateOrigin: """Tests for Origin/Referer header validation.""" def test_accepts_matching_origin(self): """Valid when Origin matches expected host.""" from animaltrack.web.middleware import validate_origin assert validate_origin("https://example.com", "example.com") is True def test_accepts_matching_origin_with_port(self): """Valid when Origin matches expected host with port.""" from animaltrack.web.middleware import validate_origin assert validate_origin("https://example.com:3366", "example.com:3366") is True def test_rejects_different_origin(self): """Invalid when Origin doesn't match expected host.""" from animaltrack.web.middleware import validate_origin assert validate_origin("https://evil.com", "example.com") is False def test_rejects_subdomain_mismatch(self): """Invalid when Origin is a subdomain of expected host.""" from animaltrack.web.middleware import validate_origin assert validate_origin("https://sub.example.com", "example.com") is False def test_accepts_none_origin(self): """None origin returns False (will check Referer instead).""" from animaltrack.web.middleware import validate_origin assert validate_origin(None, "example.com") is False def test_accepts_empty_origin(self): """Empty origin returns False.""" from animaltrack.web.middleware import validate_origin assert validate_origin("", "example.com") is False class TestValidateReferer: """Tests for Referer header validation.""" def test_accepts_matching_referer(self): """Valid when Referer host matches expected host.""" from animaltrack.web.middleware import validate_referer assert validate_referer("https://example.com/page", "example.com") is True def test_accepts_matching_referer_with_port(self): """Valid when Referer matches expected host with port.""" from animaltrack.web.middleware import validate_referer assert validate_referer("https://example.com:3366/page", "example.com:3366") is True def test_rejects_different_referer(self): """Invalid when Referer host doesn't match expected host.""" from animaltrack.web.middleware import validate_referer assert validate_referer("https://evil.com/page", "example.com") is False def test_rejects_none_referer(self): """Invalid when Referer is None.""" from animaltrack.web.middleware import validate_referer assert validate_referer(None, "example.com") is False def test_rejects_empty_referer(self): """Invalid when Referer is empty.""" from animaltrack.web.middleware import validate_referer assert validate_referer("", "example.com") is False def test_rejects_malformed_referer(self): """Invalid when Referer is malformed.""" from animaltrack.web.middleware import validate_referer assert validate_referer("not-a-url", "example.com") is False