[MM-18625] Fix database source parsing on go 1.12.8 (#12250)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
33cf37bbc0
Коммит
05fae599b8
@@ -8,6 +8,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
@@ -22,6 +23,8 @@ import (
|
|||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var tcpStripper = regexp.MustCompile(`@tcp\((.*)\)`)
|
||||||
|
|
||||||
// DatabaseStore is a config store backed by a database.
|
// DatabaseStore is a config store backed by a database.
|
||||||
type DatabaseStore struct {
|
type DatabaseStore struct {
|
||||||
commonStore
|
commonStore
|
||||||
@@ -101,23 +104,22 @@ func initializeConfigurationsTable(db *sqlx.DB) error {
|
|||||||
// By contrast, a Postgres DSN is returned unmodified.
|
// By contrast, a Postgres DSN is returned unmodified.
|
||||||
func parseDSN(dsn string) (string, string, error) {
|
func parseDSN(dsn string) (string, string, error) {
|
||||||
// Treat the DSN as the URL that it is.
|
// Treat the DSN as the URL that it is.
|
||||||
u, err := url.Parse(dsn)
|
s := strings.SplitN(dsn, "://", 2)
|
||||||
if err != nil {
|
if len(s) != 2 {
|
||||||
return "", "", errors.Wrap(err, "failed to parse DSN as URL")
|
errors.New("failed to parse DSN as URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme := u.Scheme
|
scheme := s[0]
|
||||||
switch scheme {
|
switch scheme {
|
||||||
case "mysql":
|
case "mysql":
|
||||||
// Strip off the mysql:// for the dsn with which to connect.
|
// Strip off the mysql:// for the dsn with which to connect.
|
||||||
u.Scheme = ""
|
dsn = s[1]
|
||||||
dsn = strings.TrimPrefix(u.String(), "//")
|
|
||||||
|
|
||||||
case "postgres":
|
case "postgres":
|
||||||
// No changes required
|
// No changes required
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "", "", errors.Wrapf(err, "unsupported scheme %s", scheme)
|
return "", "", errors.Errorf("unsupported scheme %s", scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
return scheme, dsn, nil
|
return scheme, dsn, nil
|
||||||
@@ -293,7 +295,11 @@ func (ds *DatabaseStore) RemoveFile(name string) error {
|
|||||||
|
|
||||||
// String returns the path to the database backing the config, masking the password.
|
// String returns the path to the database backing the config, masking the password.
|
||||||
func (ds *DatabaseStore) String() string {
|
func (ds *DatabaseStore) String() string {
|
||||||
u, _ := url.Parse(ds.originalDsn)
|
// Remove @tcp and the parentheses from the host and parse the rest as a URL
|
||||||
|
u, err := url.Parse(tcpStripper.ReplaceAllString(ds.originalDsn, `@$1`))
|
||||||
|
if err != nil {
|
||||||
|
return "(omitted due to error parsing the DSN)"
|
||||||
|
}
|
||||||
|
|
||||||
// Strip out the password to avoid leaking in logs.
|
// Strip out the password to avoid leaking in logs.
|
||||||
u.User = url.User(u.User.Username())
|
u.User = url.User(u.User.Username())
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package config_test
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -137,6 +136,11 @@ func TestDatabaseStoreNew(t *testing.T) {
|
|||||||
_, err := config.NewDatabaseStore("invalid")
|
_, err := config.NewDatabaseStore("invalid")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("unsupported scheme with valid data source", func(t *testing.T) {
|
||||||
|
_, err := config.NewDatabaseStore(fmt.Sprintf("invalid://%s", *sqlSettings.DataSource))
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDatabaseStoreGet(t *testing.T) {
|
func TestDatabaseStoreGet(t *testing.T) {
|
||||||
@@ -930,14 +934,11 @@ func TestDatabaseStoreString(t *testing.T) {
|
|||||||
sqlSettings := mainHelper.GetSqlSettings()
|
sqlSettings := mainHelper.GetSqlSettings()
|
||||||
ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource))
|
ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, ds)
|
||||||
defer ds.Close()
|
defer ds.Close()
|
||||||
|
|
||||||
actualStringURL, err := url.Parse(ds.String())
|
maskedDSN := ds.String()
|
||||||
require.NoError(t, err)
|
assert.True(t, strings.HasPrefix(maskedDSN, "mysql://"))
|
||||||
|
assert.True(t, strings.Contains(maskedDSN, "mmuser"))
|
||||||
assert.Equal(t, *sqlSettings.DriverName, actualStringURL.Scheme)
|
assert.False(t, strings.Contains(maskedDSN, "mostest"))
|
||||||
actualUsername := actualStringURL.User.Username()
|
|
||||||
actualPassword, _ := actualStringURL.User.Password()
|
|
||||||
assert.NotEmpty(t, actualUsername)
|
|
||||||
assert.Empty(t, actualPassword, "should mask password")
|
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user