feat: backend service
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Package clientip exposes the helper that resolves the originating client
|
||||
// IP for an inbound HTTP request. Backend trusts the value because the
|
||||
// network segment between gateway and backend is the trust boundary
|
||||
// (`ARCHITECTURE.md` §15-16): gateway is responsible for sanitising and
|
||||
// populating `X-Forwarded-For` before the request reaches backend.
|
||||
//
|
||||
// Both the public-auth handler chain (handlers_auth_helpers.go) and the
|
||||
// user-surface geo-counter middleware reuse the same extraction so the two
|
||||
// surfaces never disagree about the IP they record.
|
||||
package clientip
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ExtractSourceIP returns the originating client IP for the request behind
|
||||
// c. The leftmost entry of `X-Forwarded-For` is preferred; when the header
|
||||
// is absent or empty, the connection RemoteAddr is used (with the port
|
||||
// stripped). The empty string is returned when neither source yields a
|
||||
// usable value, which lets callers treat the result as "no IP available"
|
||||
// and skip dependent work.
|
||||
func ExtractSourceIP(c *gin.Context) string {
|
||||
if c == nil || c.Request == nil {
|
||||
return ""
|
||||
}
|
||||
if xff := c.GetHeader("X-Forwarded-For"); xff != "" {
|
||||
first := xff
|
||||
if idx := strings.IndexByte(first, ','); idx >= 0 {
|
||||
first = first[:idx]
|
||||
}
|
||||
return strings.TrimSpace(first)
|
||||
}
|
||||
addr := c.Request.RemoteAddr
|
||||
if host, _, err := net.SplitHostPort(addr); err == nil {
|
||||
return host
|
||||
}
|
||||
return addr
|
||||
}
|
||||
Reference in New Issue
Block a user