diff --git a/app/public_routes.py b/app/public_routes.py index fea47902..9143aa23 100644 --- a/app/public_routes.py +++ b/app/public_routes.py @@ -34,6 +34,8 @@ UNSUPPORTED_PUBLIC_PATHS_SUMMARY, ) +WALLET_SEARCH_QUERY_MAX_LENGTH = 500 + def _bounties_api_url( status: str | None, @@ -181,6 +183,11 @@ def public_bounties_context( def wallets_page_context(session: Session, q: str | None = None) -> dict[str, Any]: if q is not None and contains_control_character(q): raise HTTPException(status_code=400, detail="q must not contain control characters") + if q is not None and len(q) > WALLET_SEARCH_QUERY_MAX_LENGTH: + raise HTTPException( + status_code=400, + detail=f"q must be at most {WALLET_SEARCH_QUERY_MAX_LENGTH} characters", + ) query_text = q.strip() if q is not None else "" query = select(Wallet) if query_text: diff --git a/tests/test_wallet_api.py b/tests/test_wallet_api.py index e65b0684..96803256 100644 --- a/tests/test_wallet_api.py +++ b/tests/test_wallet_api.py @@ -740,6 +740,8 @@ def test_wallet_pages_reject_control_character_filters(sqlite_url: str) -> None: repeated_search_response = client.get("/wallets?q=Main&q=smoke") masked_type_response = client.get(f"/wallets/{address}?type=%C2%85test_funding&type=all") repeated_type_response = client.get(f"/wallets/{address}?type=test_funding&type=all") + max_length_search_response = client.get("/wallets", params={"q": "a" * 500}) + oversized_search_response = client.get("/wallets", params={"q": "a" * 501}) assert search_response.status_code == 400 assert search_response.json()["detail"] == "q must not contain control characters" @@ -756,6 +758,9 @@ def test_wallet_pages_reject_control_character_filters(sqlite_url: str) -> None: ) assert repeated_type_response.status_code == 400 assert repeated_type_response.json()["detail"] == "type must be provided at most once" + assert max_length_search_response.status_code == 200 + assert oversized_search_response.status_code == 400 + assert oversized_search_response.json()["detail"] == "q must be at most 500 characters" def test_me_page_shows_signed_in_github_claim_balance(sqlite_url: str, monkeypatch) -> None: