Merge pull request #2658 from creativeprojects/issue-2241

Don't echo authentication passwords (rest backend)
This commit is contained in:
MichaelEischer
2020-09-22 22:17:53 +02:00
committed by GitHub
6 changed files with 172 additions and 21 deletions

View File

@@ -0,0 +1,96 @@
package location
import "testing"
var passwordTests = []struct {
input string
expected string
}{
{
"local:/srv/repo",
"local:/srv/repo",
},
{
"/dir1/dir2",
"/dir1/dir2",
},
{
`c:\dir1\foobar\dir2`,
`c:\dir1\foobar\dir2`,
},
{
"sftp:user@host:/srv/repo",
"sftp:user@host:/srv/repo",
},
{
"s3://eu-central-1/bucketname",
"s3://eu-central-1/bucketname",
},
{
"swift:container17:/prefix97",
"swift:container17:/prefix97",
},
{
"b2:bucketname:/prefix",
"b2:bucketname:/prefix",
},
{
"rest:",
"rest:/",
},
{
"rest:localhost/",
"rest:localhost/",
},
{
"rest::123/",
"rest::123/",
},
{
"rest:http://",
"rest:http://",
},
{
"rest:http://hostname.foo:1234/",
"rest:http://hostname.foo:1234/",
},
{
"rest:http://user@hostname.foo:1234/",
"rest:http://user@hostname.foo:1234/",
},
{
"rest:http://user:@hostname.foo:1234/",
"rest:http://user:***@hostname.foo:1234/",
},
{
"rest:http://user:p@hostname.foo:1234/",
"rest:http://user:***@hostname.foo:1234/",
},
{
"rest:http://user:pppppaaafhhfuuwiiehhthhghhdkjaoowpprooghjjjdhhwuuhgjsjhhfdjhruuhsjsdhhfhshhsppwufhhsjjsjs@hostname.foo:1234/",
"rest:http://user:***@hostname.foo:1234/",
},
{
"rest:http://user:password@hostname",
"rest:http://user:***@hostname/",
},
{
"rest:http://user:password@:123",
"rest:http://user:***@:123/",
},
{
"rest:http://user:password@",
"rest:http://user:***@/",
},
}
func TestStripPassword(t *testing.T) {
for i, test := range passwordTests {
t.Run(test.input, func(t *testing.T) {
result := StripPassword(test.input)
if result != test.expected {
t.Errorf("test %d: expected '%s' but got '%s'", i, test.expected, result)
}
})
}
}

View File

@@ -24,22 +24,28 @@ type Location struct {
}
type parser struct {
scheme string
parse func(string) (interface{}, error)
scheme string
parse func(string) (interface{}, error)
stripPassword func(string) string
}
// parsers is a list of valid config parsers for the backends. The first parser
// is the fallback and should always be set to the local backend.
var parsers = []parser{
{"b2", b2.ParseConfig},
{"local", local.ParseConfig},
{"sftp", sftp.ParseConfig},
{"s3", s3.ParseConfig},
{"gs", gs.ParseConfig},
{"azure", azure.ParseConfig},
{"swift", swift.ParseConfig},
{"rest", rest.ParseConfig},
{"rclone", rclone.ParseConfig},
{"b2", b2.ParseConfig, noPassword},
{"local", local.ParseConfig, noPassword},
{"sftp", sftp.ParseConfig, noPassword},
{"s3", s3.ParseConfig, noPassword},
{"gs", gs.ParseConfig, noPassword},
{"azure", azure.ParseConfig, noPassword},
{"swift", swift.ParseConfig, noPassword},
{"rest", rest.ParseConfig, rest.StripPassword},
{"rclone", rclone.ParseConfig, noPassword},
}
// noPassword returns the repository location unchanged (there's no sensitive information there)
func noPassword(s string) string {
return s
}
func isPath(s string) bool {
@@ -107,6 +113,19 @@ func Parse(s string) (u Location, err error) {
return u, nil
}
// StripPassword returns a displayable version of a repository location (with any sensitive information removed)
func StripPassword(s string) string {
scheme := extractScheme(s)
for _, parser := range parsers {
if parser.scheme != scheme {
continue
}
return parser.stripPassword(s)
}
return s
}
func extractScheme(s string) string {
data := strings.SplitN(s, ":", 2)
return data[0]

View File

@@ -31,10 +31,7 @@ func ParseConfig(s string) (interface{}, error) {
return nil, errors.New("invalid REST backend specification")
}
s = s[5:]
if !strings.HasSuffix(s, "/") {
s += "/"
}
s = prepareURL(s)
u, err := url.Parse(s)
@@ -46,3 +43,31 @@ func ParseConfig(s string) (interface{}, error) {
cfg.URL = u
return cfg, nil
}
// StripPassword removes the password from the URL
// If the repository location cannot be parsed as a valid URL, it will be returned as is
// (it's because this function is used for logging errors)
func StripPassword(s string) string {
scheme := s[:5]
s = prepareURL(s)
u, err := url.Parse(s)
if err != nil {
return scheme + s
}
if _, set := u.User.Password(); !set {
return scheme + s
}
// a password was set: we replace it with ***
return scheme + strings.Replace(u.String(), u.User.String()+"@", u.User.Username()+":***@", 1)
}
func prepareURL(s string) string {
s = s[5:]
if !strings.HasSuffix(s, "/") {
s += "/"
}
return s
}