package auth import ( "net" "net/http" "strings" ) // DirectRemoteIP returns the direct TCP peer address, ignoring X-Forwarded-For. // Use for security decisions (login rate limit, IP rules, resource auth). func DirectRemoteIP(r *http.Request) string { return HostOnly(r.RemoteAddr) } // AddrHost extracts the host portion from a net.Addr string (host:port or [host]:port). func AddrHost(addr net.Addr) string { if addr == nil { return "" } return HostOnly(addr.String()) } // HostOnly strips the port from an address string. func HostOnly(addr string) string { if addr == "" { return "" } host, _, err := net.SplitHostPort(addr) if err != nil { return strings.Trim(addr, "[]") } return host } // ExtractRemoteIP returns the client IP, honoring X-Forwarded-For when present. // Use only when forwarding visitor IP to upstream backends behind a trusted proxy. func ExtractRemoteIP(r *http.Request) string { if xff := r.Header.Get("X-Forwarded-For"); xff != "" { parts := strings.Split(xff, ",") return strings.TrimSpace(parts[0]) } if xri := r.Header.Get("X-Real-IP"); xri != "" { return strings.TrimSpace(xri) } return DirectRemoteIP(r) } // SafeRedirectPath validates a post-login redirect path (relative only). func SafeRedirectPath(raw string) string { raw = strings.TrimSpace(raw) if raw == "" || !strings.HasPrefix(raw, "/") || strings.HasPrefix(raw, "//") { return "/" } return raw }