From b713a4daf110e0af4acd7673408dbb735200a0fe Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Mon, 21 Sep 2026 11:30:01 +0330 Subject: [PATCH] fix(zarinhub): limit upstream response size --- backend/internal/zarinhub/client.go | 14 +++++++++- backend/internal/zarinhub/client_test.go | 33 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/backend/internal/zarinhub/client.go b/backend/internal/zarinhub/client.go index d3d6e41..19d9455 100644 --- a/backend/internal/zarinhub/client.go +++ b/backend/internal/zarinhub/client.go @@ -13,6 +13,8 @@ import ( "card-to-iban/internal/service" ) +const maxResponseBodySize = 1 << 20 + type Client struct { httpClient *http.Client endpointURL string @@ -95,7 +97,9 @@ func (c *Client) Convert( UpstreamHTTPStatus: resp.StatusCode, } - body, err := io.ReadAll(resp.Body) + body, err := io.ReadAll( + io.LimitReader(resp.Body, maxResponseBodySize+1), + ) if err != nil { return result, fmt.Errorf( @@ -105,6 +109,14 @@ func (c *Client) Convert( ) } + if len(body) > maxResponseBodySize { + return result, + fmt.Errorf( + "%w: response body is too large", + ErrInvalidResponse, + ) + } + result.RawResponse = body switch { diff --git a/backend/internal/zarinhub/client_test.go b/backend/internal/zarinhub/client_test.go index 86ccdf1..9a85923 100644 --- a/backend/internal/zarinhub/client_test.go +++ b/backend/internal/zarinhub/client_test.go @@ -381,3 +381,36 @@ func TestClientReturnsTimeout(t *testing.T) { ) } } + +func TestClientRejectsOversizedResponse(t *testing.T) { + server := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + + body := make([]byte, maxResponseBodySize+1) + for index := range body { + body[index] = 'x' + } + + if _, err := w.Write(body); err != nil { + t.Errorf("write response: %v", err) + } + }), + ) + defer server.Close() + + client := NewClient( + &http.Client{Timeout: time.Second}, + server.URL, + "test-token", + ) + + _, err := client.Convert( + context.Background(), + "6037997512345678", + ) + + if !errors.Is(err, ErrInvalidResponse) { + t.Fatalf("error = %v, want ErrInvalidResponse", err) + } +}