mirror of https://github.com/status-im/migrate.git
245 lines
10 KiB
Go
245 lines
10 KiB
Go
package database_test
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const reservedChars = "!#$%&'()*+,/:;=?@[]"
|
|
|
|
// TestUserUnencodedReservedURLChars documents the behavior of using unencoded reserved characters in usernames with
|
|
// net/url Parse()
|
|
func TestUserUnencodedReservedURLChars(t *testing.T) {
|
|
scheme := "database://"
|
|
baseUsername := "username"
|
|
urlSuffix := "password@localhost:12345/myDB?someParam=true"
|
|
urlSuffixAndSep := ":" + urlSuffix
|
|
|
|
testcases := []struct {
|
|
char string
|
|
parses bool
|
|
expectedUsername string // empty string means that the username failed to parse
|
|
encodedURL string
|
|
}{
|
|
{char: "!", parses: true, expectedUsername: baseUsername + "!",
|
|
encodedURL: scheme + baseUsername + "%21" + urlSuffixAndSep},
|
|
{char: "#", parses: true, expectedUsername: "",
|
|
encodedURL: scheme + baseUsername + "#" + urlSuffixAndSep},
|
|
{char: "$", parses: true, expectedUsername: baseUsername + "$",
|
|
encodedURL: scheme + baseUsername + "$" + urlSuffixAndSep},
|
|
{char: "%", parses: false},
|
|
{char: "&", parses: true, expectedUsername: baseUsername + "&",
|
|
encodedURL: scheme + baseUsername + "&" + urlSuffixAndSep},
|
|
{char: "'", parses: true, expectedUsername: "username'",
|
|
encodedURL: scheme + baseUsername + "%27" + urlSuffixAndSep},
|
|
{char: "(", parses: true, expectedUsername: "username(",
|
|
encodedURL: scheme + baseUsername + "%28" + urlSuffixAndSep},
|
|
{char: ")", parses: true, expectedUsername: "username)",
|
|
encodedURL: scheme + baseUsername + "%29" + urlSuffixAndSep},
|
|
{char: "*", parses: true, expectedUsername: "username*",
|
|
encodedURL: scheme + baseUsername + "%2A" + urlSuffixAndSep},
|
|
{char: "+", parses: true, expectedUsername: "username+",
|
|
encodedURL: scheme + baseUsername + "+" + urlSuffixAndSep},
|
|
{char: ",", parses: true, expectedUsername: "username,",
|
|
encodedURL: scheme + baseUsername + "," + urlSuffixAndSep},
|
|
{char: "/", parses: true, expectedUsername: "",
|
|
encodedURL: scheme + baseUsername + "/" + urlSuffixAndSep},
|
|
{char: ":", parses: true, expectedUsername: "username",
|
|
encodedURL: scheme + baseUsername + ":%3A" + urlSuffix},
|
|
{char: ";", parses: true, expectedUsername: "username;",
|
|
encodedURL: scheme + baseUsername + ";" + urlSuffixAndSep},
|
|
{char: "=", parses: true, expectedUsername: "username=",
|
|
encodedURL: scheme + baseUsername + "=" + urlSuffixAndSep},
|
|
{char: "?", parses: true, expectedUsername: "",
|
|
encodedURL: scheme + baseUsername + "?" + urlSuffixAndSep},
|
|
{char: "@", parses: true, expectedUsername: "username@",
|
|
encodedURL: scheme + baseUsername + "%40" + urlSuffixAndSep},
|
|
{char: "[", parses: false},
|
|
{char: "]", parses: false},
|
|
}
|
|
|
|
testedChars := make([]string, 0, len(reservedChars))
|
|
for _, tc := range testcases {
|
|
testedChars = append(testedChars, tc.char)
|
|
t.Run("reserved char "+tc.char, func(t *testing.T) {
|
|
s := scheme + baseUsername + tc.char + urlSuffixAndSep
|
|
u, err := url.Parse(s)
|
|
if err == nil {
|
|
if !tc.parses {
|
|
t.Error("Unexpectedly parsed reserved character. url:", s)
|
|
return
|
|
}
|
|
var username string
|
|
if u.User != nil {
|
|
username = u.User.Username()
|
|
}
|
|
if username != tc.expectedUsername {
|
|
t.Error("Got unexpected username:", username, "!=", tc.expectedUsername)
|
|
}
|
|
if s := u.String(); s != tc.encodedURL {
|
|
t.Error("Got unexpected encoded URL:", s, "!=", tc.encodedURL)
|
|
}
|
|
} else {
|
|
if tc.parses {
|
|
t.Error("Failed to parse reserved character. url:", s)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("All reserved chars tested", func(t *testing.T) {
|
|
if s := strings.Join(testedChars, ""); s != reservedChars {
|
|
t.Error("Not all reserved URL characters were tested:", s, "!=", reservedChars)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestUserEncodedReservedURLChars(t *testing.T) {
|
|
scheme := "database://"
|
|
baseUsername := "username"
|
|
urlSuffix := "password@localhost:12345/myDB?someParam=true"
|
|
urlSuffixAndSep := ":" + urlSuffix
|
|
|
|
for _, c := range reservedChars {
|
|
c := string(c)
|
|
t.Run("reserved char "+c, func(t *testing.T) {
|
|
encodedChar := "%" + hex.EncodeToString([]byte(c))
|
|
s := scheme + baseUsername + encodedChar + urlSuffixAndSep
|
|
expectedUsername := baseUsername + c
|
|
u, err := url.Parse(s)
|
|
if err != nil {
|
|
t.Fatal("Failed to parse url with encoded reserved character. url:", s)
|
|
}
|
|
if u.User == nil {
|
|
t.Fatal("Failed to parse userinfo with encoded reserve character. url:", s)
|
|
}
|
|
if username := u.User.Username(); username != expectedUsername {
|
|
t.Fatal("Got unexpected username:", username, "!=", expectedUsername)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestPasswordUnencodedReservedURLChars documents the behavior of using unencoded reserved characters in passwords
|
|
// with net/url Parse()
|
|
func TestPasswordUnencodedReservedURLChars(t *testing.T) {
|
|
username := "username"
|
|
schemeAndUsernameAndSep := "database://" + username + ":"
|
|
basePassword := "password"
|
|
urlSuffixAndSep := "@localhost:12345/myDB?someParam=true"
|
|
|
|
testcases := []struct {
|
|
char string
|
|
parses bool
|
|
expectedUsername string // empty string means that the username failed to parse
|
|
expectedPassword string // empty string means that the password failed to parse
|
|
encodedURL string
|
|
}{
|
|
{char: "!", parses: true, expectedUsername: username, expectedPassword: basePassword + "!",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "%21" + urlSuffixAndSep},
|
|
{char: "#", parses: true, expectedUsername: "", expectedPassword: "",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "#" + urlSuffixAndSep},
|
|
{char: "$", parses: true, expectedUsername: username, expectedPassword: basePassword + "$",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "$" + urlSuffixAndSep},
|
|
{char: "%", parses: false},
|
|
{char: "&", parses: true, expectedUsername: username, expectedPassword: basePassword + "&",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "&" + urlSuffixAndSep},
|
|
{char: "'", parses: true, expectedUsername: username, expectedPassword: "password'",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "%27" + urlSuffixAndSep},
|
|
{char: "(", parses: true, expectedUsername: username, expectedPassword: "password(",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "%28" + urlSuffixAndSep},
|
|
{char: ")", parses: true, expectedUsername: username, expectedPassword: "password)",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "%29" + urlSuffixAndSep},
|
|
{char: "*", parses: true, expectedUsername: username, expectedPassword: "password*",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "%2A" + urlSuffixAndSep},
|
|
{char: "+", parses: true, expectedUsername: username, expectedPassword: "password+",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "+" + urlSuffixAndSep},
|
|
{char: ",", parses: true, expectedUsername: username, expectedPassword: "password,",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "," + urlSuffixAndSep},
|
|
{char: "/", parses: true, expectedUsername: "", expectedPassword: "",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "/" + urlSuffixAndSep},
|
|
{char: ":", parses: true, expectedUsername: username, expectedPassword: "password:",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "%3A" + urlSuffixAndSep},
|
|
{char: ";", parses: true, expectedUsername: username, expectedPassword: "password;",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + ";" + urlSuffixAndSep},
|
|
{char: "=", parses: true, expectedUsername: username, expectedPassword: "password=",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "=" + urlSuffixAndSep},
|
|
{char: "?", parses: true, expectedUsername: "", expectedPassword: "",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "?" + urlSuffixAndSep},
|
|
{char: "@", parses: true, expectedUsername: username, expectedPassword: "password@",
|
|
encodedURL: schemeAndUsernameAndSep + basePassword + "%40" + urlSuffixAndSep},
|
|
{char: "[", parses: false},
|
|
{char: "]", parses: false},
|
|
}
|
|
|
|
testedChars := make([]string, 0, len(reservedChars))
|
|
for _, tc := range testcases {
|
|
testedChars = append(testedChars, tc.char)
|
|
t.Run("reserved char "+tc.char, func(t *testing.T) {
|
|
s := schemeAndUsernameAndSep + basePassword + tc.char + urlSuffixAndSep
|
|
u, err := url.Parse(s)
|
|
if err == nil {
|
|
if !tc.parses {
|
|
t.Error("Unexpectedly parsed reserved character. url:", s)
|
|
return
|
|
}
|
|
var username, password string
|
|
if u.User != nil {
|
|
username = u.User.Username()
|
|
password, _ = u.User.Password()
|
|
}
|
|
if username != tc.expectedUsername {
|
|
t.Error("Got unexpected username:", username, "!=", tc.expectedUsername)
|
|
}
|
|
if password != tc.expectedPassword {
|
|
t.Error("Got unexpected password:", password, "!=", tc.expectedPassword)
|
|
}
|
|
if s := u.String(); s != tc.encodedURL {
|
|
t.Error("Got unexpected encoded URL:", s, "!=", tc.encodedURL)
|
|
}
|
|
} else {
|
|
if tc.parses {
|
|
t.Error("Failed to parse reserved character. url:", s)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
t.Run("All reserved chars tested", func(t *testing.T) {
|
|
if s := strings.Join(testedChars, ""); s != reservedChars {
|
|
t.Error("Not all reserved URL characters were tested:", s, "!=", reservedChars)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPasswordEncodedReservedURLChars(t *testing.T) {
|
|
username := "username"
|
|
schemeAndUsernameAndSep := "database://" + username + ":"
|
|
basePassword := "password"
|
|
urlSuffixAndSep := "@localhost:12345/myDB?someParam=true"
|
|
|
|
for _, c := range reservedChars {
|
|
c := string(c)
|
|
t.Run("reserved char "+c, func(t *testing.T) {
|
|
encodedChar := "%" + hex.EncodeToString([]byte(c))
|
|
s := schemeAndUsernameAndSep + basePassword + encodedChar + urlSuffixAndSep
|
|
expectedPassword := basePassword + c
|
|
u, err := url.Parse(s)
|
|
if err != nil {
|
|
t.Fatal("Failed to parse url with encoded reserved character. url:", s)
|
|
}
|
|
if u.User == nil {
|
|
t.Fatal("Failed to parse userinfo with encoded reserve character. url:", s)
|
|
}
|
|
if n := u.User.Username(); n != username {
|
|
t.Fatal("Got unexpected username:", n, "!=", username)
|
|
}
|
|
if p, _ := u.User.Password(); p != expectedPassword {
|
|
t.Fatal("Got unexpected password:", p, "!=", expectedPassword)
|
|
}
|
|
})
|
|
}
|
|
}
|