From 43a9002017bec966bf753de8faaaf859858b1eb4 Mon Sep 17 00:00:00 2001 From: Phloraxx Date: Fri, 7 Aug 2026 15:16:25 +0000 Subject: [PATCH] Prevent PayGate search indexing --- internal/api/api.go | 9 +++++++++ internal/api/operations_test.go | 12 ++++++++++-- internal/api/razorpay.go | 1 + web/index.html | 1 + 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/internal/api/api.go b/internal/api/api.go index 69cc532..b2264b8 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -38,6 +38,7 @@ const ( maxStatementRequestBytes int64 = reconciliation.MaxFileBytes + (1 << 20) maxRazorpayTestRequestBytes int64 = 1 << 20 maxRazorpayLiveRequestBytes int64 = 1 << 20 + robotsTagValue = "noindex, nofollow, noarchive, nosnippet, noimageindex" ) type API struct { @@ -60,6 +61,14 @@ func New(cfg config.Config, paymentService *payments.Service, smsService *sms.Se func (a *API) Register(app core.App) { app.OnServe().BindFunc(func(e *core.ServeEvent) error { + e.Router.BindFunc(func(event *core.RequestEvent) error { + event.Response.Header().Set("X-Robots-Tag", robotsTagValue) + return event.Next() + }) + e.Router.GET("/robots.txt", func(event *core.RequestEvent) error { + event.Response.Header().Set("Cache-Control", "no-store") + return event.String(http.StatusOK, "User-agent: *\nDisallow:\n") + }) e.Router.POST("/api/payments", a.createPayment).Bind(apis.BodyLimit(maxPaymentRequestBytes)) e.Router.GET("/api/payments/{id}", a.getPayment) e.Router.POST("/api/payments/{id}/cancel", a.cancelPayment) diff --git a/internal/api/operations_test.go b/internal/api/operations_test.go index 2ff03e9..e51aa1e 100644 --- a/internal/api/operations_test.go +++ b/internal/api/operations_test.go @@ -274,15 +274,23 @@ func TestOperatorSPAUsesSecurityHeadersAndRejectsUnknownBrowserRoutes(t *testing if res.StatusCode != http.StatusOK || !bytes.Contains(data, []byte("PayGate")) { t.Fatalf("root status=%d body=%s", res.StatusCode, data) } - for _, name := range []string{"Content-Security-Policy", "Permissions-Policy", "Referrer-Policy", "Strict-Transport-Security"} { + for _, name := range []string{"Content-Security-Policy", "Permissions-Policy", "Referrer-Policy", "Strict-Transport-Security", "X-Robots-Tag"} { if res.Header.Get(name) == "" { t.Fatalf("missing %s", name) } } - for _, path := range []string{"/contact/", "/robots.txt", "/sitemap.xml"} { + res, robots := fixture.request(t, http.MethodGet, "/robots.txt", nil, "", false) + if res.StatusCode != http.StatusOK || !bytes.Contains(robots, []byte("User-agent: *")) || res.Header.Get("X-Robots-Tag") == "" { + t.Fatalf("robots status=%d header=%q body=%s", res.StatusCode, res.Header.Get("X-Robots-Tag"), robots) + } + for _, path := range []string{"/contact/", "/sitemap.xml"} { res, _ := fixture.request(t, http.MethodGet, path, nil, "", false) if res.StatusCode != http.StatusNotFound { t.Fatalf("%s status=%d", path, res.StatusCode) } } + res, _ = fixture.request(t, http.MethodGet, "/api/config", nil, "", true) + if res.Header.Get("X-Robots-Tag") == "" { + t.Fatal("missing X-Robots-Tag on API response") + } } diff --git a/internal/api/razorpay.go b/internal/api/razorpay.go index 8f5d2b6..1bfc0cb 100644 --- a/internal/api/razorpay.go +++ b/internal/api/razorpay.go @@ -156,4 +156,5 @@ func (a *API) setOperatorSecurityHeaders(e *core.RequestEvent) { headers.Set("Strict-Transport-Security", "max-age=31536000") headers.Set("X-Content-Type-Options", "nosniff") headers.Set("X-Frame-Options", "DENY") + headers.Set("X-Robots-Tag", robotsTagValue) } diff --git a/web/index.html b/web/index.html index e2421dd..9f828a5 100644 --- a/web/index.html +++ b/web/index.html @@ -3,6 +3,7 @@ + PayGate