From 96143fa251ef90525d9fc4ab7226edf2810a903e Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 2 Jun 2026 07:18:10 +0200 Subject: [PATCH] fix: replace deprecated chi middleware.RealIP in internal router chi v5.3.0 deprecates middleware.RealIP (staticcheck SA1019). The internal API is gated by InternalToken and its client sends a single trusted X-Real-IP header, so replace it with a small local middleware that reads X-Real-IP and sets RemoteAddr, preserving the previous behavior. Assisted-by: claude-code:opus-4.8 --- routers/private/internal.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/routers/private/internal.go b/routers/private/internal.go index 36cd4429565..114f9e7528d 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -6,6 +6,7 @@ package private import ( "crypto/subtle" + "net" "net/http" "strings" @@ -18,7 +19,6 @@ import ( "gitea.dev/services/context" "gitea.com/go-chi/binding" - chi_middleware "github.com/go-chi/chi/v5/middleware" ) func authInternal(next http.Handler) http.Handler { @@ -50,6 +50,18 @@ func bind[T any](_ T) any { } } +// setRealIP sets RemoteAddr from the trusted X-Real-IP header set by the internal API +// client (see modules/private.NewInternalRequest); the internal API is gated by InternalToken. +// It replaces chi's deprecated middleware.RealIP, which is unsafe on public-facing endpoints. +func setRealIP(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if ip := req.Header.Get("X-Real-IP"); net.ParseIP(ip) != nil { + req.RemoteAddr = ip + } + next.ServeHTTP(w, req) + }) +} + // Routes registers all internal APIs routes to web application. // These APIs will be invoked by internal commands for example `gitea serv` and etc. func Routes() *web.Router { @@ -58,7 +70,7 @@ func Routes() *web.Router { r.AfterRouting(authInternal) // Log the real ip address of the request from SSH is really helpful for diagnosing sometimes. // Since internal API will be sent only from Gitea sub commands and it's under control (checked by InternalToken), we can trust the headers. - r.AfterRouting(chi_middleware.RealIP) + r.AfterRouting(setRealIP) r.Get("/dummy", misc.DummyOK) r.Post("/ssh/authorized_keys", AuthorizedPublicKeyByContent)