fear(client): extract client's IP and store in database and structured logs
This commit is contained in:
@@ -248,6 +248,10 @@ func TestHandlerConvert(t *testing.T) {
|
||||
t.Errorf("masked card = %q, want %q", record.MaskedCard, tt.wantMaskedCard)
|
||||
}
|
||||
|
||||
if record.ClientIP == nil || *record.ClientIP != "192.0.2.1" {
|
||||
t.Errorf("client IP = %v, want 192.0.2.1", record.ClientIP)
|
||||
}
|
||||
|
||||
if strings.Contains(string(record.ResponseJSON), "6037997512345678") {
|
||||
t.Error("audit response contains the full card number")
|
||||
}
|
||||
@@ -291,3 +295,75 @@ func TestHandlerFailsClosedWhenAuditSaveFails(t *testing.T) {
|
||||
t.Errorf("response body = %s, want internal_error", response.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerExtractsClientIP(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
headerKey string
|
||||
headerVal string
|
||||
remoteAddr string
|
||||
wantIP string
|
||||
}{
|
||||
{
|
||||
name: "prefers CF-Connecting-IP",
|
||||
headerKey: "CF-Connecting-IP",
|
||||
headerVal: "203.0.113.88",
|
||||
remoteAddr: "10.0.0.1:1234",
|
||||
wantIP: "203.0.113.88",
|
||||
},
|
||||
{
|
||||
name: "prefers X-Forwarded-For over RemoteAddr",
|
||||
headerKey: "X-Forwarded-For",
|
||||
headerVal: "198.51.100.77, 10.0.0.2",
|
||||
remoteAddr: "10.0.0.1:1234",
|
||||
wantIP: "198.51.100.77",
|
||||
},
|
||||
{
|
||||
name: "uses RemoteAddr host without port",
|
||||
remoteAddr: "192.168.10.5:9999",
|
||||
wantIP: "192.168.10.5",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
audits := &fakeAuditSaver{}
|
||||
handler := NewHandler(
|
||||
&fakeConverter{
|
||||
result: service.ConversionResult{
|
||||
IBAN: "IR820540102680020817909002",
|
||||
UpstreamHTTPStatus: http.StatusOK,
|
||||
},
|
||||
},
|
||||
audits,
|
||||
slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||
)
|
||||
|
||||
req := httptest.NewRequest(
|
||||
http.MethodPost,
|
||||
"/api/v1/card-to-iban",
|
||||
strings.NewReader(`{"card":"6037997512345678"}`),
|
||||
)
|
||||
if tt.headerKey != "" {
|
||||
req.Header.Set(tt.headerKey, tt.headerVal)
|
||||
}
|
||||
req.RemoteAddr = tt.remoteAddr
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
handler.Convert(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200", rec.Code)
|
||||
}
|
||||
|
||||
if len(audits.records) != 1 {
|
||||
t.Fatalf("audit records count = %d, want 1", len(audits.records))
|
||||
}
|
||||
|
||||
recIP := audits.records[0].ClientIP
|
||||
if recIP == nil || *recIP != tt.wantIP {
|
||||
t.Errorf("ClientIP = %v, want %q", recIP, tt.wantIP)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user