Use clientip.Extract for esign and session IP capture

Several HTTP entry points still parsed RemoteAddr directly, so behind
a layer-7 proxy they recorded the load balancer IP instead of the
signer's. Route NDA acceptance, signing events, document sign/approve,
and session updates through clientip.Extract, which honors Forwarded
and X-Forwarded-For when trustedproxy allows them.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
Ludovic Vielle
2026-07-06 11:43:39 +02:00
parent 119b20bfbc
commit 1116fc6bb4
5 changed files with 51 additions and 37 deletions

View File

@@ -27,28 +27,38 @@ import (
// load balancer closest to us.
func Extract(r *http.Request) string {
if fwd := r.Header.Get("Forwarded"); fwd != "" {
if ip := parseForwardedFor(fwd); ip != "" {
if ip := parseForwardedFor(fwd); net.ParseIP(ip) != nil {
return ip
}
}
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
if i := strings.LastIndexByte(xff, ','); i != -1 {
xff = xff[i+1:]
}
xff = strings.TrimSpace(xff)
if ip, _, err := net.SplitHostPort(xff); err == nil {
if ip := parseXForwardedFor(xff); net.ParseIP(ip) != nil {
return ip
}
return xff
}
ip, _, err := net.SplitHostPort(r.RemoteAddr)
return extractRemoteAddr(r.RemoteAddr)
}
func parseXForwardedFor(xff string) string {
if i := strings.LastIndexByte(xff, ','); i != -1 {
xff = xff[i+1:]
}
xff = strings.TrimSpace(xff)
if ip, _, err := net.SplitHostPort(xff); err == nil {
return ip
}
return xff
}
func extractRemoteAddr(remoteAddr string) string {
ip, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return r.RemoteAddr
return remoteAddr
}
return ip

View File

@@ -110,6 +110,27 @@ func TestExtract(t *testing.T) {
headers: map[string]string{"Forwarded": "for=198.51.100.17;proto=https;by=203.0.113.60"},
want: "198.51.100.17",
},
{
name: "unparseable forwarded falls back to remote addr",
remoteAddr: "10.0.0.1:1234",
headers: map[string]string{"Forwarded": "for=unknown"},
want: "10.0.0.1",
},
{
name: "unparseable x-forwarded-for falls back to remote addr",
remoteAddr: "10.0.0.1:1234",
headers: map[string]string{"X-Forwarded-For": "unknown"},
want: "10.0.0.1",
},
{
name: "unparseable forwarded falls through to x-forwarded-for",
remoteAddr: "10.0.0.1:1234",
headers: map[string]string{
"Forwarded": "for=unknown",
"X-Forwarded-For": "203.0.113.50",
},
want: "203.0.113.50",
},
}
for _, tt := range tests {