diff --git a/src/net/url/url.go b/src/net/url/url.go index 6480d4b432242b..74b1ccec1e8caa 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -821,6 +821,16 @@ func (u *URL) String() string { return buf.String() } +// Redacted returns a password-redacted version of the String() method, only if +// the password exists. The password is substituted by "xxxxx". +func (u *URL) Redacted() string { + rdkt := *u + if _, has := rdkt.User.Password(); has { + rdkt.User = UserPassword(rdkt.User.Username(), "xxxxx") + } + return rdkt.String() +} + // Values maps a string key to a list of values. // It is typically used for query parameters and form values. // Unlike in the http.Header map, the keys in a Values map diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index 79fd3d5c79f37f..bb4660128a46b2 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -765,6 +765,74 @@ func TestURLString(t *testing.T) { } } +var maskedURLTestsPtr = []struct { + url *URL + want string + shouldMask bool +}{ + { + url: &URL{ + Scheme: "http", + Host: "host.tld", + Path: "this:that", + User: UserPassword("user", "password"), + }, + want: "http://user:xxxxx@host.tld/this:that", + shouldMask: true, + }, + { + url: &URL{ + Scheme: "http", + Host: "host.tld", + Path: "this:that", + User: User("user"), + }, + want: "http://user@host.tld/this:that", + shouldMask: false, + }, +} + +var redactedURLTests = []struct { + url *URL + want string +}{ + { + url: &URL{ + Scheme: "http", + Host: "host.tld", + Path: "this:that", + User: UserPassword("user", "password"), + }, + want: "http://user:xxxxx@host.tld/this:that", + }, + { + url: &URL{ + Scheme: "http", + Host: "host.tld", + Path: "this:that", + User: User("user"), + }, + want: "http://user@host.tld/this:that", + }, +} + +func TestURLRedacted(t *testing.T) { + for _, tt := range redactedURLTests { + if got := tt.url.Redacted(); got != tt.want { + t.Errorf("%+v.Redacted() = %q; want %q", tt.url, got, tt.want) + } + } + for _, tt := range maskedURLTestsPtr { + if got := tt.url.Redacted(); got != tt.want { + t.Errorf("%+v.Redacted() = %q; want %q", tt.url, got, tt.want) + } + + if tt.shouldMask && tt.url.Redacted() == tt.url.String() { + t.Errorf("%+v.Redacted() password should differ to %+v.String()", tt.url, tt.url) + } + } +} + type EscapeTest struct { in string out string