diff --git a/main.go b/main.go index 8452277..99909f7 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "log" "net/url" "os" + "regexp" "github.com/joho/godotenv" "github.com/urfave/cli" @@ -19,7 +20,8 @@ func main() { err := app.Run(os.Args) if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Error: %s\n", err) + errText := redactLogString(fmt.Sprintf("Error: %s\n", err)) + _, _ = fmt.Fprint(os.Stderr, errText) os.Exit(2) } } @@ -219,3 +221,10 @@ func getDatabaseURL(c *cli.Context) (u *url.URL, err error) { return url.Parse(value) } + +// redactLogString attempts to redact passwords from errors +func redactLogString(in string) string { + re := regexp.MustCompile("([a-zA-Z]+://[^:]+:)[^@]+@") + + return re.ReplaceAllString(in, "${1}********@") +} diff --git a/main_test.go b/main_test.go index 1d20d06..d6922db 100644 --- a/main_test.go +++ b/main_test.go @@ -35,3 +35,23 @@ func TestGetDatabaseUrl(t *testing.T) { require.Equal(t, "example.org", u.Host) require.Equal(t, "/db", u.Path) } + +func TestRedactLogString(t *testing.T) { + examples := []struct { + in string + expected string + }{ + {"normal string", + "normal string"}, + // malformed URL example (note forward slash in password) + {"parse \"mysql://username:otS33+tb/e4=@localhost:3306/database\": invalid", + "parse \"mysql://username:********@localhost:3306/database\": invalid"}, + // invalid port, but probably not a password since there is no @ + {"parse \"mysql://localhost:abc/database\": invalid", + "parse \"mysql://localhost:abc/database\": invalid"}, + } + + for _, ex := range examples { + require.Equal(t, ex.expected, redactLogString(ex.in)) + } +}