diff --git a/internal/debug/round_tripper_debug.go b/internal/debug/round_tripper_debug.go index 339c49833..020e798f0 100644 --- a/internal/debug/round_tripper_debug.go +++ b/internal/debug/round_tripper_debug.go @@ -75,12 +75,31 @@ func RoundTripper(upstream http.RoundTripper) http.RoundTripper { return eofRoundTripper } +func redactHeader(header http.Header) map[string][]string { + removedHeaders := make(map[string][]string) + for _, hdr := range []string{ + "Authorization", + "X-Auth-Token", // Swift headers + "X-Auth-Key", + } { + origHeader, hasHeader := header[hdr] + if hasHeader { + removedHeaders[hdr] = origHeader + header[hdr] = []string{"**redacted**"} + } + } + return removedHeaders +} + +func restoreHeader(header http.Header, origHeaders map[string][]string) { + for hdr, val := range origHeaders { + header[hdr] = val + } +} + func (tr loggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, err error) { // save original auth and redact it - origAuth, hasAuth := req.Header["Authorization"] - if hasAuth { - req.Header["Authorization"] = []string{"**redacted**"} - } + origHeaders := redactHeader(req.Header) trace, err := httputil.DumpRequestOut(req, false) if err != nil { @@ -89,10 +108,7 @@ func (tr loggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, Log("------------ HTTP REQUEST -----------\n%s", trace) } - // restore auth - if hasAuth { - req.Header["Authorization"] = origAuth - } + restoreHeader(req.Header, origHeaders) res, err = tr.RoundTripper.RoundTrip(req) if err != nil { @@ -100,7 +116,9 @@ func (tr loggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, } if res != nil { + origHeaders := redactHeader(res.Header) trace, err := httputil.DumpResponse(res, false) + restoreHeader(res.Header, origHeaders) if err != nil { Log("DumpResponse() error: %v\n", err) } else { diff --git a/internal/debug/round_tripper_debug_test.go b/internal/debug/round_tripper_debug_test.go new file mode 100644 index 000000000..2095bbc6e --- /dev/null +++ b/internal/debug/round_tripper_debug_test.go @@ -0,0 +1,46 @@ +// +build debug + +package debug + +import ( + "net/http" + "testing" + + "github.com/restic/restic/internal/test" +) + +func TestRedactHeader(t *testing.T) { + secretHeaders := []string{ + "Authorization", + "X-Auth-Token", + "X-Auth-Key", + } + + header := make(http.Header) + header["Authorization"] = []string{"123"} + header["X-Auth-Token"] = []string{"1234"} + header["X-Auth-Key"] = []string{"12345"} + header["Host"] = []string{"my.host"} + + origHeaders := redactHeader(header) + + for _, hdr := range secretHeaders { + test.Equals(t, "**redacted**", header[hdr][0]) + } + test.Equals(t, "my.host", header["Host"][0]) + + restoreHeader(header, origHeaders) + test.Equals(t, "123", header["Authorization"][0]) + test.Equals(t, "1234", header["X-Auth-Token"][0]) + test.Equals(t, "12345", header["X-Auth-Key"][0]) + test.Equals(t, "my.host", header["Host"][0]) + + delete(header, "X-Auth-Key") + origHeaders = redactHeader(header) + _, hasHeader := header["X-Auth-Key"] + test.Assert(t, !hasHeader, "Unexpected header: %v", header["X-Auth-Key"]) + + restoreHeader(header, origHeaders) + _, hasHeader = header["X-Auth-Key"] + test.Assert(t, !hasHeader, "Unexpected header: %v", header["X-Auth-Key"]) +}