Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TT-9464] Reverting URL encoding changes #79

Merged
merged 5 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions persistent/internal/driver/mgo/life_cycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ type lifeCycle struct {

// Connect connects to the mongo database given the ClientOpts.
func (lc *lifeCycle) Connect(opts *types.ClientOpts) error {
opts.ConnectionString = helper.EncodeConnectionString(opts.ConnectionString)

dialInfo, err := mgo.ParseURL(opts.ConnectionString)
if err != nil {
return err
Expand Down
2 changes: 0 additions & 2 deletions persistent/internal/driver/mongo/life_cycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ func (lc *lifeCycle) Connect(opts *types.ClientOpts) error {
var err error
var client *mongo.Client

opts.ConnectionString = helper.EncodeConnectionString(opts.ConnectionString)

// we check if the connection string is valid before building the connOpts.
cs, err := connstring.ParseAndValidate(opts.ConnectionString)
if err != nil {
Expand Down
68 changes: 0 additions & 68 deletions persistent/internal/helper/functions.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package helper

import (
"fmt"
"log"
"net/url"
"reflect"
"strings"
)
Expand All @@ -26,69 +24,3 @@ func IsCosmosDB(connectionString string) bool {
strings.Contains(connectionString, "AccountEndpoint=") ||
strings.Contains(connectionString, "AccountKey=")
}

// EncodeConnectionString URL encodes the password and the username from the connection string.
// It's useful when they contains special characters.
// Example: mongodb://user:p@ssword@localhost:27017/db -> mongodb://user:p%40word@40localhost:27017/db
// If there's any conflict, the function returns the original connection string.
func EncodeConnectionString(connectionString string) string {
// Find the last '@' before the last ':' (the delimiter between credentials and host)
// we use ':' since the URL can contain '@' characters after the port number
at := findLastAtBeforeLastColon(connectionString)
if at == -1 {
// If there's no ':' in the connection string, we use the last '@' as delimiter
at = findLastAt(connectionString)
// If there's no '@' in the connection string, we return the original connection string
if at == -1 {
return connectionString
}
}

credentialsAndScheme := connectionString[:at]
hostAndDB := connectionString[at+1:]

// Split the credentials and scheme
credentialsAndSchemeParts := strings.SplitN(credentialsAndScheme, "://", 2)
if len(credentialsAndSchemeParts) != 2 {
return connectionString
}

scheme := credentialsAndSchemeParts[0] // here we extract the scheme
credentials := credentialsAndSchemeParts[1]

// Split the username and password
credentialsParts := strings.Split(credentials, ":")
if len(credentialsParts) < 2 {
return connectionString
}

username := credentialsParts[0]
password := strings.Join(credentialsParts[1:], ":")

// URL encode the password
encodedPassword := url.QueryEscape(password)

encodedUsername := url.QueryEscape(username)

// Construct the new connection string
newConnectionString := fmt.Sprintf("%s://%s:%s@%s", scheme, encodedUsername, encodedPassword, hostAndDB)

return newConnectionString
}

func findLastAtBeforeLastColon(str string) int {
lastColon := strings.LastIndex(str, ":")
if lastColon == -1 {
return -1
}

subStr := str[:lastColon]

lastAt := strings.LastIndex(subStr, "@")

return lastAt
}

func findLastAt(str string) int {
return strings.LastIndex(str, "@")
}
91 changes: 0 additions & 91 deletions persistent/internal/helper/functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,94 +61,3 @@ func TestIsCosmosDB(t *testing.T) {
}
}
}

func TestEncodeConnectionString(t *testing.T) {
tests := []struct {
name string
originalConnString string
expectedConnString string
}{
{
name: "valid connection string",
originalConnString: "mongodb://user:password@localhost:27017/test",
expectedConnString: "mongodb://user:password@localhost:27017/test",
},
{
name: "valid connection string with @",
originalConnString: "mongodb://user:p@ssword@localhost:27017",
expectedConnString: "mongodb://user:p%40ssword@localhost:27017",
},
{
name: "valid connection string with @ and /",
originalConnString: "mongodb://u=s@r:p@sswor/d@localhost:27017/test",
expectedConnString: "mongodb://u%3Ds%40r:p%40sswor%2Fd@localhost:27017/test",
},
{
name: "valid connection string with @ and / and '?' outside of the credentials part",
originalConnString: "mongodb://user:p@sswor/d@localhost:27017/test?authSource=admin",
expectedConnString: "mongodb://user:p%40sswor%2Fd@localhost:27017/test?authSource=admin",
},
{
name: "special characters and multiple hosts",
originalConnString: "mongodb://user:p@sswor/d@localhost:27017,localhost:27018/test?authSource=admin",
expectedConnString: "mongodb://user:p%40sswor%2Fd@localhost:27017,localhost:27018/test?authSource=admin",
},
{
name: "url without credentials",
originalConnString: "mongodb://localhost:27017/test?authSource=admin",
expectedConnString: "mongodb://localhost:27017/test?authSource=admin",
},
{
name: "invalid connection string",
originalConnString: "test",
expectedConnString: "test",
},
{
name: "connection string full of special characters",
originalConnString: "mongodb://user:p@ss:/?#[]wor/d@localhost:27017,localhost:27018",
expectedConnString: "mongodb://user:p%40ss%3A%2F%3F%23%5B%5Dwor%2Fd@localhost:27017,localhost:27018",
},
{
name: "srv connection string",
originalConnString: "mongodb+srv://tyk:tyk@clur0.zlgl.mongodb.net/tyk?w=majority",
expectedConnString: "mongodb+srv://tyk:tyk@clur0.zlgl.mongodb.net/tyk?w=majority",
},
{
name: "srv connection string with special characters",
originalConnString: "mongodb+srv://tyk:p@ssword@clur0.zlgl.mongodb.net/tyk?w=majority",
expectedConnString: "mongodb+srv://tyk:p%40ssword@clur0.zlgl.mongodb.net/tyk?w=majority",
},
{
name: "connection string without username",
originalConnString: "mongodb://:password@localhost:27017/test",
expectedConnString: "mongodb://:password@localhost:27017/test",
},
{
name: "connection string without password",
originalConnString: "mongodb://user:@localhost:27017/test",
expectedConnString: "mongodb://user:@localhost:27017/test",
},
{
name: "connection string without host",
originalConnString: "mongodb://user:password@/test",
expectedConnString: "mongodb://user:password@/test",
},
{
name: "connection string without database",
originalConnString: "mongodb://user:password@localhost:27017",
expectedConnString: "mongodb://user:password@localhost:27017",
},
{
name: "cosmosdb url",
originalConnString: "mongodb://4-0-qa:zFAQ==@4-0-qa.azure:10/a1?maxIdleTimeMS=120000&appName=@4-testing@",
expectedConnString: "mongodb://4-0-qa:zFAQ%3D%3D@4-0-qa.azure:10/a1?maxIdleTimeMS=120000&appName=@4-testing@",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
connString := EncodeConnectionString(test.originalConnString)
assert.Equal(t, test.expectedConnString, connString)
})
}
}