mirror of
https://github.com/jackc/pgx.git
synced 2025-05-31 11:42:24 +00:00
redact passwords in parse config errors
Redact passwords when printing the parseConfigError in a best effort manner. This prevents people from leaking the password into logs, if they just print the error in logs.
This commit is contained in:
parent
a1b9eb4d4e
commit
f27e874d55
30
errors.go
30
errors.go
@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
errors "golang.org/x/xerrors"
|
errors "golang.org/x/xerrors"
|
||||||
@ -98,10 +100,11 @@ type parseConfigError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *parseConfigError) Error() string {
|
func (e *parseConfigError) Error() string {
|
||||||
|
connString := redactPW(e.connString)
|
||||||
if e.err == nil {
|
if e.err == nil {
|
||||||
return fmt.Sprintf("cannot parse `%s`: %s", e.connString, e.msg)
|
return fmt.Sprintf("cannot parse `%s`: %s", connString, e.msg)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("cannot parse `%s`: %s (%s)", e.connString, e.msg, e.err.Error())
|
return fmt.Sprintf("cannot parse `%s`: %s (%s)", connString, e.msg, e.err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *parseConfigError) Unwrap() error {
|
func (e *parseConfigError) Unwrap() error {
|
||||||
@ -164,3 +167,26 @@ func (e *writeError) SafeToRetry() bool {
|
|||||||
func (e *writeError) Unwrap() error {
|
func (e *writeError) Unwrap() error {
|
||||||
return e.err
|
return e.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func redactPW(connString string) string {
|
||||||
|
if strings.HasPrefix(connString, "postgres://") || strings.HasPrefix(connString, "postgresql://") {
|
||||||
|
if u, err := url.Parse(connString); err == nil {
|
||||||
|
return redactURL(u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
quotedDSN := regexp.MustCompile(`password='[^']*'`)
|
||||||
|
connString = quotedDSN.ReplaceAllLiteralString(connString, "password=xxxxx")
|
||||||
|
plainDSN := regexp.MustCompile(`password=[^ ]*`)
|
||||||
|
connString = plainDSN.ReplaceAllLiteralString(connString, "password=xxxxx")
|
||||||
|
return connString
|
||||||
|
}
|
||||||
|
|
||||||
|
func redactURL(u *url.URL) string {
|
||||||
|
if u == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if _, pwSet := u.User.Password(); pwSet {
|
||||||
|
u.User = url.UserPassword(u.User.Username(), "xxxxx")
|
||||||
|
}
|
||||||
|
return u.String()
|
||||||
|
}
|
||||||
|
44
errors_test.go
Normal file
44
errors_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package pgconn_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jackc/pgconn"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfigError(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
expectedMsg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "url with password",
|
||||||
|
err: pgconn.NewParseConfigError("postgresql://foo:password@host", "msg", nil),
|
||||||
|
expectedMsg: "cannot parse `postgresql://foo:xxxxx@host`: msg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dsn with password unquoted",
|
||||||
|
err: pgconn.NewParseConfigError("host=host password=password user=user", "msg", nil),
|
||||||
|
expectedMsg: "cannot parse `host=host password=xxxxx user=user`: msg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dsn with password quoted",
|
||||||
|
err: pgconn.NewParseConfigError("host=host password='pass word' user=user", "msg", nil),
|
||||||
|
expectedMsg: "cannot parse `host=host password=xxxxx user=user`: msg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "weird url",
|
||||||
|
err: pgconn.NewParseConfigError("postgresql://foo::pasword@host:1:", "msg", nil),
|
||||||
|
expectedMsg: "cannot parse `postgresql://foo:xxxxx@host:1:`: msg",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
assert.EqualError(t, tt.err, tt.expectedMsg)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
11
export_test.go
Normal file
11
export_test.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// File export_test exports some methods for better testing.
|
||||||
|
|
||||||
|
package pgconn
|
||||||
|
|
||||||
|
func NewParseConfigError(conn, msg string, err error) error {
|
||||||
|
return &parseConfigError{
|
||||||
|
connString: conn,
|
||||||
|
msg: msg,
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user