Files
defiQUG bdae5a9f6e feat: explorer API, wallet, CCIP scripts, and config refresh
- Backend REST/gateway/track routes, analytics, Blockscout proxy paths.
- Frontend wallet and liquidity surfaces; MetaMask token list alignment.
- Deployment docs, verification scripts, address inventory updates.

Check: go build ./... under backend/ (pass).
Made-with: Cursor
2026-04-07 23:22:12 -07:00

112 lines
2.1 KiB
Go

package httpmiddleware
import (
"net"
"net/http"
"os"
"strings"
)
// ClientIP returns the best-known client IP for a request.
//
// Forwarded headers are only trusted when the immediate remote address belongs
// to an explicitly trusted proxy listed in TRUST_PROXY_IPS and/or
// TRUST_PROXY_CIDRS.
func ClientIP(r *http.Request) string {
remoteIP := parseRemoteIP(r.RemoteAddr)
if remoteIP == "" {
remoteIP = strings.TrimSpace(r.RemoteAddr)
}
if !isTrustedProxy(remoteIP) {
return remoteIP
}
if forwarded := forwardedClientIP(r); forwarded != "" {
return forwarded
}
return remoteIP
}
func parseRemoteIP(raw string) string {
trimmed := strings.TrimSpace(raw)
if trimmed == "" {
return ""
}
if host, _, err := net.SplitHostPort(trimmed); err == nil {
return host
}
if ip := net.ParseIP(trimmed); ip != nil {
return ip.String()
}
return trimmed
}
func forwardedClientIP(r *http.Request) string {
for _, header := range []string{"X-Forwarded-For", "X-Real-IP"} {
raw := strings.TrimSpace(r.Header.Get(header))
if raw == "" {
continue
}
if header == "X-Forwarded-For" {
for _, part := range strings.Split(raw, ",") {
candidate := strings.TrimSpace(part)
if ip := net.ParseIP(candidate); ip != nil {
return ip.String()
}
}
continue
}
if ip := net.ParseIP(raw); ip != nil {
return ip.String()
}
}
return ""
}
func isTrustedProxy(remoteIP string) bool {
ip := net.ParseIP(strings.TrimSpace(remoteIP))
if ip == nil {
return false
}
for _, exact := range splitEnvList("TRUST_PROXY_IPS") {
if trusted := net.ParseIP(exact); trusted != nil && trusted.Equal(ip) {
return true
}
}
for _, cidr := range splitEnvList("TRUST_PROXY_CIDRS") {
_, network, err := net.ParseCIDR(cidr)
if err == nil && network.Contains(ip) {
return true
}
}
return false
}
func splitEnvList(key string) []string {
raw := strings.TrimSpace(os.Getenv(key))
if raw == "" {
return nil
}
parts := strings.Split(raw, ",")
values := make([]string, 0, len(parts))
for _, part := range parts {
trimmed := strings.TrimSpace(part)
if trimmed != "" {
values = append(values, trimmed)
}
}
return values
}