diff --git a/Makefile b/Makefile index c0ba7109a..363b3cec8 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ swagger-console: @echo "Generating swagger server code from yaml" @swagger generate server -A console --main-package=management --server-package=api --exclude-main -P models.Principal -f ./swagger.yml -r NOTICE @echo "Generating typescript api" - @npx swagger-typescript-api -p ./swagger.yml -o ./web-app/src/api -n consoleApi.ts + @npx swagger-typescript-api -p ./swagger.yml -o ./web-app/src/api -n consoleApi.ts --custom-config generator.config.js @git restore api/server.go diff --git a/api/admin_groups.go b/api/admin_groups.go index 90c56003b..94c1f37e6 100644 --- a/api/admin_groups.go +++ b/api/admin_groups.go @@ -22,7 +22,6 @@ import ( "github.com/go-openapi/errors" "github.com/go-openapi/runtime/middleware" "github.com/minio/console/api/operations" - "github.com/minio/console/pkg/utils" "github.com/minio/madmin-go/v3" groupApi "github.com/minio/console/api/operations/group" @@ -118,12 +117,7 @@ func getGroupInfoResponse(session *models.Principal, params groupApi.GroupInfoPa // defining the client to be used adminClient := AdminClient{Client: mAdmin} - groupName, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - - groupDesc, err := groupInfo(ctx, adminClient, groupName) + groupDesc, err := groupInfo(ctx, adminClient, params.Name) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -212,12 +206,7 @@ func getRemoveGroupResponse(session *models.Principal, params groupApi.RemoveGro // defining the client to be used adminClient := AdminClient{Client: mAdmin} - groupName, err := utils.DecodeBase64(params.Name) - if err != nil { - return ErrorWithContext(ctx, err) - } - - if err := removeGroup(ctx, adminClient, groupName); err != nil { + if err := removeGroup(ctx, adminClient, params.Name); err != nil { minioError := madmin.ToErrorResponse(err) err2 := ErrorWithContext(ctx, err) if minioError.Code == "XMinioAdminNoSuchGroup" { @@ -293,11 +282,6 @@ func getUpdateGroupResponse(session *models.Principal, params groupApi.UpdateGro } expectedGroupUpdate := params.Body - groupName, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) if err != nil { return nil, ErrorWithContext(ctx, err) @@ -306,7 +290,7 @@ func getUpdateGroupResponse(session *models.Principal, params groupApi.UpdateGro // defining the client to be used adminClient := AdminClient{Client: mAdmin} - groupUpdated, err := groupUpdate(ctx, adminClient, groupName, expectedGroupUpdate) + groupUpdated, err := groupUpdate(ctx, adminClient, params.Name, expectedGroupUpdate) if err != nil { return nil, ErrorWithContext(ctx, err) } diff --git a/api/admin_inspect.go b/api/admin_inspect.go index 6774cd655..dc0bab75a 100644 --- a/api/admin_inspect.go +++ b/api/admin_inspect.go @@ -22,7 +22,6 @@ import ( "io" "net/http" "strings" - "unicode/utf8" "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" @@ -35,14 +34,6 @@ import ( func registerInspectHandler(api *operations.ConsoleAPI) { api.InspectInspectHandler = inspectApi.InspectHandlerFunc(func(params inspectApi.InspectParams, principal *models.Principal) middleware.Responder { - if v, err := base64.URLEncoding.DecodeString(params.File); err == nil && utf8.Valid(v) { - params.File = string(v) - } - - if v, err := base64.URLEncoding.DecodeString(params.Volume); err == nil && utf8.Valid(v) { - params.Volume = string(v) - } - k, r, err := getInspectResult(principal, ¶ms) if err != nil { return inspectApi.NewInspectDefault(err.Code).WithPayload(err.APIError) diff --git a/api/admin_objects.go b/api/admin_objects.go index cfb17c008..e6a97e733 100644 --- a/api/admin_objects.go +++ b/api/admin_objects.go @@ -18,7 +18,6 @@ package api import ( "context" - "encoding/base64" "time" "github.com/minio/mc/cmd" @@ -60,20 +59,7 @@ type ObjectResponse struct { func getObjectsOptionsFromReq(request ObjectsRequest) (*objectsListOpts, error) { pOptions := objectsListOpts{ BucketName: request.BucketName, - Prefix: "", - } - - prefix := request.Prefix - - if prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - LogError("error decoding prefix: %v", err) - return nil, err - } - - pOptions.Prefix = string(decodedPrefix) + Prefix: request.Prefix, } if request.Mode == "rewind" { diff --git a/api/admin_policies.go b/api/admin_policies.go index a400e476e..f8ca2d01b 100644 --- a/api/admin_policies.go +++ b/api/admin_policies.go @@ -26,7 +26,6 @@ import ( bucketApi "github.com/minio/console/api/operations/bucket" policyApi "github.com/minio/console/api/operations/policy" - "github.com/minio/console/pkg/utils" s3 "github.com/minio/minio-go/v7" "github.com/go-openapi/runtime/middleware" @@ -308,10 +307,6 @@ func getListPoliciesResponse(session *models.Principal, params policyApi.ListPol func getListUsersForPolicyResponse(session *models.Principal, params policyApi.ListUsersForPolicyParams) ([]string, *CodedAPIError) { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - policy, err := utils.DecodeBase64(params.Policy) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) if err != nil { return nil, ErrorWithContext(ctx, err) @@ -325,12 +320,12 @@ func getListUsersForPolicyResponse(session *models.Principal, params policyApi.L } found := false for i := range policies { - if policies[i].Name == policy { + if policies[i].Name == params.Policy { found = true } } if !found { - return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy)) + return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", params.Policy)) } users, err := listUsers(ctx, adminClient) if err != nil { @@ -340,7 +335,7 @@ func getListUsersForPolicyResponse(session *models.Principal, params policyApi.L var filteredUsers []string for _, user := range users { for _, upolicy := range user.Policy { - if upolicy == policy { + if upolicy == params.Policy { filteredUsers = append(filteredUsers, user.AccessKey) break } @@ -397,12 +392,7 @@ func getSAUserPolicyResponse(session *models.Principal, params policyApi.GetSAUs } userAdminClient := AdminClient{Client: mAdminClient} - userName, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - - user, err := getUserInfo(ctx, userAdminClient, userName) + user, err := getUserInfo(ctx, userAdminClient, params.Name) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -467,10 +457,6 @@ func getListGroupsForPolicyResponse(session *models.Principal, params policyApi. } // create a minioClient interface implementation // defining the client to be used - policy, err := utils.DecodeBase64(params.Policy) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } adminClient := AdminClient{Client: mAdmin} policies, err := listPolicies(ctx, adminClient) if err != nil { @@ -478,12 +464,12 @@ func getListGroupsForPolicyResponse(session *models.Principal, params policyApi. } found := false for i := range policies { - if policies[i].Name == policy { + if policies[i].Name == params.Policy { found = true } } if !found { - return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", policy)) + return nil, ErrorWithContext(ctx, ErrPolicyNotFound, fmt.Errorf("the policy %s does not exist", params.Policy)) } groups, err := adminClient.listGroups(ctx) @@ -499,7 +485,7 @@ func getListGroupsForPolicyResponse(session *models.Principal, params policyApi. } groupPolicies := strings.Split(info.Policy, ",") for _, groupPolicy := range groupPolicies { - if groupPolicy == policy { + if groupPolicy == params.Policy { filteredGroups = append(filteredGroups, group) } } @@ -524,10 +510,6 @@ func getRemovePolicyResponse(session *models.Principal, params policyApi.RemoveP if params.Name == "" { return ErrorWithContext(ctx, ErrPolicyNameNotInRequest) } - policyName, err := utils.DecodeBase64(params.Name) - if err != nil { - return ErrorWithContext(ctx, err) - } mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) if err != nil { return ErrorWithContext(ctx, err) @@ -536,7 +518,7 @@ func getRemovePolicyResponse(session *models.Principal, params policyApi.RemoveP // defining the client to be used adminClient := AdminClient{Client: mAdmin} - if err := removePolicy(ctx, adminClient, policyName); err != nil { + if err := removePolicy(ctx, adminClient, params.Name); err != nil { return ErrorWithContext(ctx, err) } return nil @@ -623,11 +605,7 @@ func getPolicyInfoResponse(session *models.Principal, params policyApi.PolicyInf // create a MinIO Admin Client interface implementation // defining the client to be used adminClient := AdminClient{Client: mAdmin} - policyName, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - policy, err := policyInfo(ctx, adminClient, policyName) + policy, err := policyInfo(ctx, adminClient, params.Name) if err != nil { return nil, ErrorWithContext(ctx, err) } diff --git a/api/admin_users.go b/api/admin_users.go index e0b51155f..b37296a11 100644 --- a/api/admin_users.go +++ b/api/admin_users.go @@ -22,8 +22,6 @@ import ( "sort" "strings" - "github.com/minio/console/pkg/utils" - "github.com/go-openapi/errors" "github.com/go-openapi/runtime/middleware" "github.com/minio/console/api/operations" @@ -257,17 +255,13 @@ func getRemoveUserResponse(session *models.Principal, params userApi.RemoveUserP if err != nil { return ErrorWithContext(ctx, err) } - userName, err := utils.DecodeBase64(params.Name) - if err != nil { - return ErrorWithContext(ctx, err) - } - if session.AccountAccessKey == userName { + if session.AccountAccessKey == params.Name { return ErrorWithContext(ctx, ErrAvoidSelfAccountDelete) } // create a minioClient interface implementation // defining the client to be used adminClient := AdminClient{Client: mAdmin} - if err := removeUser(ctx, adminClient, userName); err != nil { + if err := removeUser(ctx, adminClient, params.Name); err != nil { return ErrorWithContext(ctx, err) } return nil @@ -295,12 +289,7 @@ func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoPa // defining the client to be used adminClient := AdminClient{Client: mAdmin} - userName, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - - user, err := getUserInfo(ctx, adminClient, userName) + user, err := getUserInfo(ctx, adminClient, params.Name) if err != nil { // User doesn't exist, return 404 if madmin.ToErrorResponse(err).Code == "XMinioAdminNoSuchUser" { @@ -335,7 +324,7 @@ func getUserInfoResponse(session *models.Principal, params userApi.GetUserInfoPa } userInformation := &models.User{ - AccessKey: userName, + AccessKey: params.Name, MemberOf: user.MemberOf, Policy: policies, Status: string(user.Status), @@ -446,12 +435,7 @@ func getUpdateUserGroupsResponse(session *models.Principal, params userApi.Updat // defining the client to be used adminClient := AdminClient{Client: mAdmin} - userName, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - - user, err := updateUserGroups(ctx, adminClient, userName, params.Body.Groups) + user, err := updateUserGroups(ctx, adminClient, params.Name, params.Body.Groups) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -486,18 +470,14 @@ func getUpdateUserResponse(session *models.Principal, params userApi.UpdateUserI // create a minioClient interface implementation // defining the client to be used adminClient := AdminClient{Client: mAdmin} - userName, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } status := *params.Body.Status groups := params.Body.Groups - if err := setUserStatus(ctx, adminClient, userName, status); err != nil { + if err := setUserStatus(ctx, adminClient, params.Name, status); err != nil { return nil, ErrorWithContext(ctx, err) } - userElem, errUG := updateUserGroups(ctx, adminClient, userName, groups) + userElem, errUG := updateUserGroups(ctx, adminClient, params.Name, groups) if errUG != nil { return nil, ErrorWithContext(ctx, errUG) diff --git a/api/public_objects.go b/api/public_objects.go index 8dccfbbdb..cb0ee0777 100644 --- a/api/public_objects.go +++ b/api/public_objects.go @@ -17,7 +17,6 @@ package api import ( - b64 "encoding/base64" "fmt" "io" "net/http" @@ -45,7 +44,7 @@ func registerPublicObjectsHandlers(api *operations.ConsoleAPI) { func getDownloadPublicObjectResponse(params public.DownloadSharedObjectParams) (middleware.Responder, *CodedAPIError) { ctx := params.HTTPRequest.Context() - inputURLDecoded, err := b64toMinIOStringURL(params.URL) + inputURLDecoded, err := checkMinIOStringURL(params.URL) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -91,23 +90,19 @@ func getDownloadPublicObjectResponse(params public.DownloadSharedObjectParams) ( }), nil } -// b64toMinIOStringURL decodes url and validates is a MinIO url endpoint -func b64toMinIOStringURL(inputEncodedURL string) (*string, error) { - inputURLDecoded, err := b64.URLEncoding.DecodeString(inputEncodedURL) - if err != nil { - return nil, err - } +// checkMinIOStringURL decodes url and validates is a MinIO url endpoint +func checkMinIOStringURL(inputURL string) (*string, error) { // Validate input URL - inputURL, err := xnet.ParseHTTPURL(string(inputURLDecoded)) + parsedURL, err := xnet.ParseHTTPURL(inputURL) if err != nil { return nil, err } // Ensure incoming url points to MinIO Server minIOHost := getMinIOEndpoint() - if inputURL.Host != minIOHost { + if parsedURL.Host != minIOHost { return nil, ErrForbidden } - return swag.String(string(inputURLDecoded)), nil + return swag.String(inputURL), nil } func url2BucketAndObject(u *url.URL) (bucketName, objectName string) { diff --git a/api/public_objects_test.go b/api/public_objects_test.go index af0537b01..2d172de4f 100644 --- a/api/public_objects_test.go +++ b/api/public_objects_test.go @@ -23,7 +23,7 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_b64toMinIOStringURL(t *testing.T) { +func Test_checkMinIOStringURL(t *testing.T) { tAssert := assert.New(t) type args struct { encodedURL string @@ -37,7 +37,7 @@ func Test_b64toMinIOStringURL(t *testing.T) { { test: "valid encoded minIO URL returns decoded URL string", // http://localhost:9000/... args: args{ - encodedURL: "aHR0cDovL2xvY2FsaG9zdDo5MDAwL2J1Y2tldDEyMy9BdWRpbyUyMGljb24lMjgxJTI5LnN2Zz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPVVCTzFMMUM3VTg3UDFCUDI1MVRTJTJGMjAyNDA0MDUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNDA1VDIxMDEzM1omWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TZWN1cml0eS1Ub2tlbj1leUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaFkyTmxjM05MWlhraU9pSlZRazh4VERGRE4xVTROMUF4UWxBeU5URlVVeUlzSW1WNGNDSTZNVGN4TWpNNU5EQTRPU3dpY0dGeVpXNTBJam9pYldsdWFXOWhaRzFwYmlKOS5WLUtEZ3JMTVVCbG5KSEtYNlZ4SGw5LUFfLVBGRVdvazJkcFRxLTQ2YmxMbUxzdWVUeHNoVmFZNERad0dmb200VFQ1azhwaFVmZ2pjUWFuc25icmtlQSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmdmVyc2lvbklkPW51bGwmWC1BbXotU2lnbmF0dXJlPTA3Y2FkM2ViMmE2NzIyYjViYWVkMDljNmYxZmU0YTcwMWJmMTJmNDhlMTYyOGI5ZDQ1YzAxMWQ1OTU1Njc4NDU=", + encodedURL: "http://localhost:9000/bucket123/Audio%20icon%281%29.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=UBO1L1C7U87P1BP251TS%2F20240405%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240405T210133Z&X-Amz-Expires=43200&X-Amz-Security-Token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJVQk8xTDFDN1U4N1AxQlAyNTFUUyIsImV4cCI6MTcxMjM5NDA4OSwicGFyZW50IjoibWluaW9hZG1pbiJ9.V-KDgrLMUBlnJHKX6VxHl9-A_-PFEWok2dpTq-46blLmLsueTxshVaY4DZwGfom4TT5k8phUfgjcQansnbrkeA&X-Amz-SignedHeaders=host&versionId=null&X-Amz-Signature=07cad3eb2a6722b5baed09c6f1fe4a701bf12f48e1628b9d45c011d595567845", }, wantError: nil, expected: swag.String("http://localhost:9000/bucket123/Audio%20icon%281%29.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=UBO1L1C7U87P1BP251TS%2F20240405%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240405T210133Z&X-Amz-Expires=43200&X-Amz-Security-Token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJVQk8xTDFDN1U4N1AxQlAyNTFUUyIsImV4cCI6MTcxMjM5NDA4OSwicGFyZW50IjoibWluaW9hZG1pbiJ9.V-KDgrLMUBlnJHKX6VxHl9-A_-PFEWok2dpTq-46blLmLsueTxshVaY4DZwGfom4TT5k8phUfgjcQansnbrkeA&X-Amz-SignedHeaders=host&versionId=null&X-Amz-Signature=07cad3eb2a6722b5baed09c6f1fe4a701bf12f48e1628b9d45c011d595567845"), @@ -45,7 +45,7 @@ func Test_b64toMinIOStringURL(t *testing.T) { { test: "valid encoded url but not coming from MinIO server returns forbidden error", // http://non-minio-host:9000/... args: args{ - encodedURL: "aHR0cDovL25vbi1taW5pby1ob3N0OjkwMDAvYnVja2V0MTIzL0F1ZGlvJTIwaWNvbiUyODElMjkuc3ZnP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9VUJPMUwxQzdVODdQMUJQMjUxVFMlMkYyMDI0MDQwNSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA0MDVUMjEwMTMzWiZYLUFtei1FeHBpcmVzPTQzMjAwJlgtQW16LVNlY3VyaXR5LVRva2VuPWV5SmhiR2NpT2lKSVV6VXhNaUlzSW5SNWNDSTZJa3BYVkNKOS5leUpoWTJObGMzTkxaWGtpT2lKVlFrOHhUREZETjFVNE4xQXhRbEF5TlRGVVV5SXNJbVY0Y0NJNk1UY3hNak01TkRBNE9Td2ljR0Z5Wlc1MElqb2liV2x1YVc5aFpHMXBiaUo5LlYtS0RnckxNVUJsbkpIS1g2VnhIbDktQV8tUEZFV29rMmRwVHEtNDZibExtTHN1ZVR4c2hWYVk0RFp3R2ZvbTRUVDVrOHBoVWZnamNRYW5zbmJya2VBJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZ2ZXJzaW9uSWQ9bnVsbCZYLUFtei1TaWduYXR1cmU9MDdjYWQzZWIyYTY3MjJiNWJhZWQwOWM2ZjFmZTRhNzAxYmYxMmY0OGUxNjI4YjlkNDVjMDExZDU5NTU2Nzg0NQ==", + encodedURL: "http://non-minio-host:9000/bucket123/Audio%20icon%281%29.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=UBO1L1C7U87P1BP251TS%2F20240405%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240405T210133Z&X-Amz-Expires=43200&X-Amz-Security-Token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJVQk8xTDFDN1U4N1AxQlAyNTFUUyIsImV4cCI6MTcxMjM5NDA4OSwicGFyZW50IjoibWluaW9hZG1pbiJ9.V-KDgrLMUBlnJHKX6VxHl9-A_-PFEWok2dpTq-46blLmLsueTxshVaY4DZwGfom4TT5k8phUfgjcQansnbrkeA&X-Amz-SignedHeaders=host&versionId=null&X-Amz-Signature=07cad3eb2a6722b5baed09c6f1fe4a701bf12f48e1628b9d45c011d595567845", }, wantError: swag.String("403 Forbidden"), expected: nil, @@ -53,7 +53,7 @@ func Test_b64toMinIOStringURL(t *testing.T) { { test: "valid encoded url but not coming from MinIO server port returns forbidden error", // other port http://localhost:8902/... args: args{ - encodedURL: "aHR0cDovL2xvY2FsaG9zdDo4OTAyL2J1Y2tldDEyMy9BdWRpbyUyMGljb24lMjgxJTI5LnN2Zz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPVVCTzFMMUM3VTg3UDFCUDI1MVRTJTJGMjAyNDA0MDUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNDA1VDIxMDEzM1omWC1BbXotRXhwaXJlcz00MzIwMCZYLUFtei1TZWN1cml0eS1Ub2tlbj1leUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaFkyTmxjM05MWlhraU9pSlZRazh4VERGRE4xVTROMUF4UWxBeU5URlVVeUlzSW1WNGNDSTZNVGN4TWpNNU5EQTRPU3dpY0dGeVpXNTBJam9pYldsdWFXOWhaRzFwYmlKOS5WLUtEZ3JMTVVCbG5KSEtYNlZ4SGw5LUFfLVBGRVdvazJkcFRxLTQ2YmxMbUxzdWVUeHNoVmFZNERad0dmb200VFQ1azhwaFVmZ2pjUWFuc25icmtlQSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmdmVyc2lvbklkPW51bGwmWC1BbXotU2lnbmF0dXJlPTA3Y2FkM2ViMmE2NzIyYjViYWVkMDljNmYxZmU0YTcwMWJmMTJmNDhlMTYyOGI5ZDQ1YzAxMWQ1OTU1Njc4NDU=", + encodedURL: "http://localhost:8902/bucket123/Audio%20icon%281%29.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=UBO1L1C7U87P1BP251TS%2F20240405%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240405T210133Z&X-Amz-Expires=43200&X-Amz-Security-Token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJVQk8xTDFDN1U4N1AxQlAyNTFUUyIsImV4cCI6MTcxMjM5NDA4OSwicGFyZW50IjoibWluaW9hZG1pbiJ9.V-KDgrLMUBlnJHKX6VxHl9-A_-PFEWok2dpTq-46blLmLsueTxshVaY4DZwGfom4TT5k8phUfgjcQansnbrkeA&X-Amz-SignedHeaders=host&versionId=null&X-Amz-Signature=07cad3eb2a6722b5baed09c6f1fe4a701bf12f48e1628b9d45c011d595567845", }, wantError: swag.String("403 Forbidden"), expected: nil, @@ -61,7 +61,7 @@ func Test_b64toMinIOStringURL(t *testing.T) { { test: "valid url but with invalid schema returns error", args: args{ - encodedURL: "cG9zdGdyZXM6Ly9wb3N0Z3JlczoxMjM0NTZAMTI3LjAuMC4xOjU0MzIvZHVtbXk=", // postgres://postgres:123456@127.0.0.1:5432/dummy + encodedURL: "postgres://postgres:123456@127.0.0.1:5432/dummy", // postgres://postgres:123456@127.0.0.1:5432/dummy }, wantError: swag.String("unexpected scheme found postgres"), @@ -70,16 +70,16 @@ func Test_b64toMinIOStringURL(t *testing.T) { { test: "invalid url returns error", args: args{ - encodedURL: "YXNkc2Fkc2Rh", // asdsadsda + encodedURL: "asdsadsda", // asdsadsda }, wantError: swag.String("unexpected scheme found "), expected: nil, }, { - test: "encoded url is url safe decoded", + test: "plain url", args: args{ - encodedURL: "aHR0cHM6Ly9sb2NhbGhvc3Q6OTAwMC9jZXN0ZXN0L0F1ZGlvJTIwaWNvbi5zdmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTY=", + encodedURL: "https://localhost:9000/cestest/Audio%20icon.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256", }, wantError: nil, expected: swag.String("https://localhost:9000/cestest/Audio%20icon.svg?X-Amz-Algorithm=AWS4-HMAC-SHA256"), @@ -88,20 +88,20 @@ func Test_b64toMinIOStringURL(t *testing.T) { for _, tt := range tests { t.Run(tt.test, func(_ *testing.T) { - url, err := b64toMinIOStringURL(tt.args.encodedURL) + url, err := checkMinIOStringURL(tt.args.encodedURL) if tt.wantError != nil { if err != nil { if err.Error() != *tt.wantError { - t.Errorf("b64toMinIOStringURL() error: `%v`, wantErr: `%s`, input: `%s`", err, *tt.wantError, tt.args.encodedURL) + t.Errorf("checkMinIOStringURL() error: `%v`, wantErr: `%s`, input: `%s`", err, *tt.wantError, tt.args.encodedURL) return } } else { - t.Errorf("b64toMinIOStringURL() error: `%v`, wantErr: `%s`, input: `%s`", err, *tt.wantError, tt.args.encodedURL) + t.Errorf("checkMinIOStringURL() error: `%v`, wantErr: `%s`, input: `%s`", err, *tt.wantError, tt.args.encodedURL) return } } else { if err != nil { - t.Errorf("b64toMinIOStringURL() error: `%s`, wantErr: `%v`, input: `%s`", err, tt.wantError, tt.args.encodedURL) + t.Errorf("checkMinIOStringURL() error: `%s`, wantErr: `%v`, input: `%s`", err, tt.wantError, tt.args.encodedURL) return } tAssert.Equal(*tt.expected, *url) diff --git a/api/service_accounts_handlers.go b/api/service_accounts_handlers.go index c718d9821..13fe7b277 100644 --- a/api/service_accounts_handlers.go +++ b/api/service_accounts_handlers.go @@ -27,7 +27,6 @@ import ( saApi "github.com/minio/console/api/operations/service_account" userApi "github.com/minio/console/api/operations/user" "github.com/minio/console/models" - "github.com/minio/console/pkg/utils" "github.com/minio/madmin-go/v3" iampolicy "github.com/minio/pkg/v3/policy" ) @@ -199,10 +198,6 @@ func getCreateAUserServiceAccountResponse(session *models.Principal, params user // create a MinIO user Admin Client interface implementation // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} - name, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } var expiry *time.Time if params.Body.Expiry != "" { @@ -212,7 +207,7 @@ func getCreateAUserServiceAccountResponse(session *models.Principal, params user } expiry = &parsedExpiry } - saCreds, err := createAUserServiceAccount(ctx, userAdminClient, params.Body.Policy, name, params.Body.Name, params.Body.Description, expiry, params.Body.Comment) + saCreds, err := createAUserServiceAccount(ctx, userAdminClient, params.Body.Policy, params.Name, params.Body.Name, params.Body.Description, expiry, params.Body.Comment) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -233,14 +228,10 @@ func getCreateAUserServiceAccountCredsResponse(session *models.Principal, params // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} serviceAccount := params.Body - user, err := utils.DecodeBase64(params.Name) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - if user == serviceAccount.AccessKey { + if params.Name == serviceAccount.AccessKey { return nil, ErrorWithContext(ctx, errors.New("Access Key already in use")) } - accounts, err := userAdminClient.listServiceAccounts(ctx, user) + accounts, err := userAdminClient.listServiceAccounts(ctx, params.Name) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -258,7 +249,7 @@ func getCreateAUserServiceAccountCredsResponse(session *models.Principal, params } expiry = &parsedExpiry } - saCreds, err := createAUserServiceAccountCreds(ctx, userAdminClient, serviceAccount.Policy, user, serviceAccount.AccessKey, serviceAccount.SecretKey, serviceAccount.Name, serviceAccount.Description, expiry, serviceAccount.Comment) + saCreds, err := createAUserServiceAccountCreds(ctx, userAdminClient, serviceAccount.Policy, params.Name, serviceAccount.AccessKey, serviceAccount.SecretKey, serviceAccount.Name, serviceAccount.Description, expiry, serviceAccount.Comment) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -366,10 +357,6 @@ func getUserServiceAccountsResponse(ctx context.Context, session *models.Princip // create a MinIO user Admin Client interface implementation // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} - user, err = utils.DecodeBase64(user) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } serviceAccounts, err := getUserServiceAccounts(ctx, userAdminClient, user) if err != nil { return nil, ErrorWithContext(ctx, err) @@ -386,10 +373,6 @@ func deleteServiceAccount(ctx context.Context, userClient MinioAdmin, accessKey func getDeleteServiceAccountResponse(session *models.Principal, params saApi.DeleteServiceAccountParams) *CodedAPIError { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - accessKey, err := utils.DecodeBase64(params.AccessKey) - if err != nil { - return ErrorWithContext(ctx, err) - } userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) if err != nil { return ErrorWithContext(ctx, err) @@ -397,7 +380,7 @@ func getDeleteServiceAccountResponse(session *models.Principal, params saApi.Del // create a MinIO user Admin Client interface implementation // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} - if err := deleteServiceAccount(ctx, userAdminClient, accessKey); err != nil { + if err := deleteServiceAccount(ctx, userAdminClient, params.AccessKey); err != nil { return ErrorWithContext(ctx, err) } return nil @@ -441,10 +424,6 @@ func getServiceAccountDetails(ctx context.Context, userClient MinioAdmin, access func getServiceAccountInfo(session *models.Principal, params saApi.GetServiceAccountParams) (*models.ServiceAccount, *CodedAPIError) { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - accessKey, err := utils.DecodeBase64(params.AccessKey) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) if err != nil { return nil, ErrorWithContext(ctx, err) @@ -453,7 +432,7 @@ func getServiceAccountInfo(session *models.Principal, params saApi.GetServiceAcc // defining the client to be used userAdminClient := AdminClient{Client: userAdmin} - serviceAccount, err := getServiceAccountDetails(ctx, userAdminClient, accessKey) + serviceAccount, err := getServiceAccountDetails(ctx, userAdminClient, params.AccessKey) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -481,10 +460,6 @@ func updateServiceAccountDetails(ctx context.Context, userClient MinioAdmin, acc func updateSetServiceAccountResponse(session *models.Principal, params saApi.UpdateServiceAccountParams) *CodedAPIError { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - accessKey, err := utils.DecodeBase64(params.AccessKey) - if err != nil { - return ErrorWithContext(ctx, err) - } policy := *params.Body.Policy userAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session) if err != nil { @@ -502,7 +477,7 @@ func updateSetServiceAccountResponse(session *models.Principal, params saApi.Upd } expiry = &parsedExpiry } - err = updateServiceAccountDetails(ctx, userAdminClient, accessKey, policy, expiry, params.Body.Name, params.Body.Description, params.Body.Status, params.Body.SecretKey) + err = updateServiceAccountDetails(ctx, userAdminClient, params.AccessKey, policy, expiry, params.Body.Name, params.Body.Description, params.Body.Status, params.Body.SecretKey) if err != nil { return ErrorWithContext(ctx, err) } diff --git a/api/user_buckets.go b/api/user_buckets.go index a7c0dcdde..0607fd0eb 100644 --- a/api/user_buckets.go +++ b/api/user_buckets.go @@ -18,7 +18,6 @@ package api import ( "context" - "encoding/base64" "encoding/json" "errors" "fmt" @@ -1014,12 +1013,7 @@ func getBucketRewindResponse(session *models.Principal, params bucketApi.GetBuck defer cancel() prefix := "" if params.Prefix != nil { - encodedPrefix := SanitizeEncodedPrefix(*params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) + prefix = *params.Prefix } s3Client, err := newS3BucketClient(session, params.BucketName, prefix, getClientIP(params.HTTPRequest)) if err != nil { diff --git a/api/user_objects.go b/api/user_objects.go index a26946a0c..28436cd56 100644 --- a/api/user_objects.go +++ b/api/user_objects.go @@ -18,8 +18,6 @@ package api import ( "context" - "encoding/base64" - b64 "encoding/base64" "errors" "fmt" "io" @@ -79,19 +77,8 @@ func registerObjectsHandlers(api *operations.ConsoleAPI) { // download object api.ObjectDownloadObjectHandler = objectApi.DownloadObjectHandlerFunc(func(params objectApi.DownloadObjectParams, session *models.Principal) middleware.Responder { isFolder := false - ctx := params.HTTPRequest.Context() - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - apiErr := ErrorWithContext(ctx, err) - return objectApi.NewDownloadObjectDefault(400).WithPayload(apiErr.APIError) - } - prefix = string(decodedPrefix) - } - folders := strings.Split(prefix, "/") + folders := strings.Split(params.Prefix, "/") if folders[len(folders)-1] == "" { isFolder = true } @@ -197,12 +184,7 @@ func getListObjectsResponse(session *models.Principal, params objectApi.ListObje var withVersions bool var withMetadata bool if params.Prefix != nil { - encodedPrefix := SanitizeEncodedPrefix(*params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) + prefix = *params.Prefix } if params.Recursive != nil { recursive = *params.Recursive @@ -417,19 +399,10 @@ func parseRange(s string, size int64) ([]httpRange, error) { func getDownloadObjectResponse(session *models.Principal, params objectApi.DownloadObjectParams) (middleware.Responder, *CodedAPIError) { ctx := params.HTTPRequest.Context() - var prefix string mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest)) if err != nil { return nil, ErrorWithContext(ctx, err) } - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } opts := minio.GetObjectOptions{} @@ -437,7 +410,7 @@ func getDownloadObjectResponse(session *models.Principal, params objectApi.Downl opts.VersionID = *params.VersionID } - resp, err := mClient.GetObject(ctx, params.BucketName, prefix, opts) + resp, err := mClient.GetObject(ctx, params.BucketName, params.Prefix, opts) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -446,19 +419,11 @@ func getDownloadObjectResponse(session *models.Principal, params objectApi.Downl defer resp.Close() isPreview := params.Preview != nil && *params.Preview - // override filename is set - decodeOverride, err := base64.StdEncoding.DecodeString(*params.OverrideFileName) - if err != nil { - fmtError := ErrorWithContext(ctx, fmt.Errorf("unable to decode OverrideFileName: %v", err)) - http.Error(rw, fmtError.APIError.DetailedMessage, http.StatusBadRequest) - return - } - - overrideName := string(decodeOverride) + overrideName := *params.OverrideFileName // indicate it's a download / inline content to the browser, and the size of the object var filename string - prefixElements := strings.Split(prefix, "/") + prefixElements := strings.Split(params.Prefix, "/") if len(prefixElements) > 0 && overrideName == "" { if prefixElements[len(prefixElements)-1] == "" { filename = prefixElements[len(prefixElements)-2] @@ -475,7 +440,7 @@ func getDownloadObjectResponse(session *models.Principal, params objectApi.Downl stat, err := resp.Stat() if err != nil { minErr := minio.ToErrorResponse(err) - fmtError := ErrorWithContext(ctx, fmt.Errorf("failed to get Stat() response from server for %s (version %s): %v", prefix, opts.VersionID, minErr.Error())) + fmtError := ErrorWithContext(ctx, fmt.Errorf("failed to get Stat() response from server for %s (version %s): %v", params.Prefix, opts.VersionID, minErr.Error())) http.Error(rw, fmtError.APIError.DetailedMessage, http.StatusInternalServerError) return } @@ -537,18 +502,9 @@ func getDownloadObjectResponse(session *models.Principal, params objectApi.Downl func getDownloadFolderResponse(session *models.Principal, params objectApi.DownloadObjectParams) (middleware.Responder, *CodedAPIError) { ctx := params.HTTPRequest.Context() - var prefix string mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest)) - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - folders := strings.Split(prefix, "/") + folders := strings.Split(params.Prefix, "/") if err != nil { return nil, ErrorWithContext(ctx, err) @@ -558,7 +514,7 @@ func getDownloadFolderResponse(session *models.Principal, params objectApi.Downl ctx: ctx, client: minioClient, bucketName: params.BucketName, - prefix: prefix, + prefix: params.Prefix, recursive: true, withVersions: false, withMetadata: false, @@ -579,7 +535,7 @@ func getDownloadFolderResponse(session *models.Principal, params objectApi.Downl defer zipw.Close() for i, obj := range objects { - name := folder + objects[i].Name[len(prefix)-1:] + name := folder + objects[i].Name[len(params.Prefix)-1:] object, err := mClient.GetObject(ctx, params.BucketName, obj.Name, minio.GetObjectOptions{}) if err != nil { // Ignore errors, move to next @@ -609,20 +565,8 @@ func getDownloadFolderResponse(session *models.Principal, params objectApi.Downl defer resp.Close() // indicate it's a download / inline content to the browser, and the size of the object - var prefixPath string var filename string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - fmtError := ErrorWithContext(ctx, fmt.Errorf("unable to parse encoded prefix %s: %v", encodedPrefix, err)) - http.Error(rw, fmtError.APIError.DetailedMessage, http.StatusInternalServerError) - return - } - - prefixPath = string(decodedPrefix) - } - prefixElements := strings.Split(prefixPath, "/") + prefixElements := strings.Split(params.Prefix, "/") if len(prefixElements) > 0 { if prefixElements[len(prefixElements)-1] == "" { filename = prefixElements[len(prefixElements)-2] @@ -775,16 +719,7 @@ func getMultipleFilesDownloadResponse(session *models.Principal, params objectAp func getDeleteObjectResponse(session *models.Principal, params objectApi.DeleteObjectParams) *CodedAPIError { ctx, cancel := context.WithCancel(params.HTTPRequest.Context()) defer cancel() - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - s3Client, err := newS3BucketClient(session, params.BucketName, prefix, getClientIP(params.HTTPRequest)) + s3Client, err := newS3BucketClient(session, params.BucketName, params.Prefix, getClientIP(params.HTTPRequest)) if err != nil { return ErrorWithContext(ctx, err) } @@ -817,7 +752,7 @@ func getDeleteObjectResponse(session *models.Principal, params objectApi.DeleteO return ErrorWithContext(ctx, err) } - err = deleteObjects(ctx, mcClient, params.BucketName, prefix, version, rec, allVersions, nonCurrentVersions, bypass) + err = deleteObjects(ctx, mcClient, params.BucketName, params.Prefix, version, rec, allVersions, nonCurrentVersions, bypass) if err != nil { return ErrorWithContext(ctx, err) } @@ -1008,12 +943,7 @@ func getUploadObjectResponse(session *models.Principal, params objectApi.PostBuc func uploadFiles(ctx context.Context, client MinioClient, params objectApi.PostBucketsBucketNameObjectsUploadParams) error { var prefix string if params.Prefix != nil { - encodedPrefix := SanitizeEncodedPrefix(*params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return err - } - prefix = string(decodedPrefix) + prefix = *params.Prefix // trim any leading '/', since that is not expected // for any object. prefix = strings.TrimPrefix(prefix, "/") @@ -1058,16 +988,7 @@ func uploadFiles(ctx context.Context, client MinioClient, params objectApi.PostB func getShareObjectResponse(session *models.Principal, params objectApi.ShareObjectParams) (*string, *CodedAPIError) { ctx := params.HTTPRequest.Context() clientIP := utils.ClientIPFromContext(ctx) - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - s3Client, err := newS3BucketClient(session, params.BucketName, prefix, clientIP) + s3Client, err := newS3BucketClient(session, params.BucketName, params.Prefix, clientIP) if err != nil { return nil, ErrorWithContext(ctx, err) } @@ -1086,7 +1007,7 @@ func getShareObjectResponse(session *models.Principal, params objectApi.ShareObj return url, nil } -func getShareObjectURL(ctx context.Context, client MCClient, r *http.Request, versionID string, duration string) (url *string, err error) { +func getShareObjectURL(ctx context.Context, client MCClient, r *http.Request, versionID string, duration string) (*string, error) { // default duration 7d if not defined if strings.TrimSpace(duration) == "" { duration = "168h" @@ -1100,9 +1021,8 @@ func getShareObjectURL(ctx context.Context, client MCClient, r *http.Request, ve return nil, pErr.Cause } - encodedMinIOURL := b64.URLEncoding.EncodeToString([]byte(minioURL)) requestURL := getRequestURLWithScheme(r) - objURL := fmt.Sprintf("%s/api/v1/download-shared-object/%s", requestURL, encodedMinIOURL) + objURL := fmt.Sprintf("%s/api/v1/download-shared-object/%s", requestURL, url.PathEscape(minioURL)) return &objURL, nil } @@ -1129,16 +1049,7 @@ func getSetObjectLegalHoldResponse(session *models.Principal, params objectApi.P // create a minioClient interface implementation // defining the client to be used minioClient := minioClient{client: mClient} - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - err = setObjectLegalHold(ctx, minioClient, params.BucketName, prefix, params.VersionID, *params.Body.Status) + err = setObjectLegalHold(ctx, minioClient, params.BucketName, params.Prefix, params.VersionID, *params.Body.Status) if err != nil { return ErrorWithContext(ctx, err) } @@ -1164,16 +1075,7 @@ func getSetObjectRetentionResponse(session *models.Principal, params objectApi.P // create a minioClient interface implementation // defining the client to be used minioClient := minioClient{client: mClient} - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - err = setObjectRetention(ctx, minioClient, params.BucketName, params.VersionID, prefix, params.Body) + err = setObjectRetention(ctx, minioClient, params.BucketName, params.VersionID, params.Prefix, params.Body) if err != nil { return ErrorWithContext(ctx, err) } @@ -1216,16 +1118,7 @@ func deleteObjectRetentionResponse(session *models.Principal, params objectApi.D // create a minioClient interface implementation // defining the client to be used minioClient := minioClient{client: mClient} - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - err = deleteObjectRetention(ctx, minioClient, params.BucketName, prefix, params.VersionID) + err = deleteObjectRetention(ctx, minioClient, params.BucketName, params.Prefix, params.VersionID) if err != nil { return ErrorWithContext(ctx, err) } @@ -1250,16 +1143,7 @@ func getPutObjectTagsResponse(session *models.Principal, params objectApi.PutObj // create a minioClient interface implementation // defining the client to be used minioClient := minioClient{client: mClient} - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - err = putObjectTags(ctx, minioClient, params.BucketName, prefix, params.VersionID, params.Body.Tags) + err = putObjectTags(ctx, minioClient, params.BucketName, params.Prefix, params.VersionID, params.Body.Tags) if err != nil { return ErrorWithContext(ctx, err) } @@ -1287,18 +1171,7 @@ func getPutObjectRestoreResponse(session *models.Principal, params objectApi.Put // create a minioClient interface implementation // defining the client to be used minioClient := minioClient{client: mClient} - - var prefix string - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - - err = restoreObject(ctx, minioClient, params.BucketName, prefix, params.VersionID) + err = restoreObject(ctx, minioClient, params.BucketName, params.Prefix, params.VersionID) if err != nil { return ErrorWithContext(ctx, err) } @@ -1342,23 +1215,12 @@ func getObjectMetadataResponse(session *models.Principal, params objectApi.GetOb // create a minioClient interface implementation // defining the client to be used minioClient := minioClient{client: mClient} - var prefix string var versionID string - - if params.Prefix != "" { - encodedPrefix := SanitizeEncodedPrefix(params.Prefix) - decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) - if err != nil { - return nil, ErrorWithContext(ctx, err) - } - prefix = string(decodedPrefix) - } - if params.VersionID != nil { versionID = *params.VersionID } - objectInfo, err := getObjectInfo(ctx, minioClient, params.BucketName, prefix, versionID) + objectInfo, err := getObjectInfo(ctx, minioClient, params.BucketName, params.Prefix, versionID) if err != nil { return nil, ErrorWithContext(ctx, err) } diff --git a/api/user_objects_test.go b/api/user_objects_test.go index 22a1f5730..12b5d4b76 100644 --- a/api/user_objects_test.go +++ b/api/user_objects_test.go @@ -942,7 +942,7 @@ func Test_shareObject(t *testing.T) { }, wantError: nil, - expected: "http://localhost:9090/api/v1/download-shared-object/aHR0cDovL3NvbWV1cmw=", + expected: "http://localhost:9090/api/v1/download-shared-object/http:%2F%2Fsomeurl", }, { test: "return https scheme if url uses TLS", @@ -959,7 +959,7 @@ func Test_shareObject(t *testing.T) { }, wantError: nil, - expected: "https://localhost:9090/api/v1/download-shared-object/aHR0cDovL3NvbWV1cmw=", + expected: "https://localhost:9090/api/v1/download-shared-object/http:%2F%2Fsomeurl", }, { test: "returns invalid expire duration if expiration is invalid", @@ -990,7 +990,7 @@ func Test_shareObject(t *testing.T) { }, }, wantError: nil, - expected: "http://localhost:9090/api/v1/download-shared-object/aHR0cDovL3NvbWV1cmw=", + expected: "http://localhost:9090/api/v1/download-shared-object/http:%2F%2Fsomeurl", }, { test: "return error if sharefunc returns error", @@ -1022,7 +1022,7 @@ func Test_shareObject(t *testing.T) { }, }, wantError: nil, - expected: "http://localhost:9090/api/v1/download-shared-object/aHR0cHM6Ly8xMjcuMC4wLjE6OTAwMC9jZXN0ZXN0L0F1ZGlvJTIwaWNvbi5zdmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTY=", + expected: "http://localhost:9090/api/v1/download-shared-object/https:%2F%2F127.0.0.1:9000%2Fcestest%2FAudio%2520icon.svg%3FX-Amz-Algorithm=AWS4-HMAC-SHA256", }, { test: "returns redirect url with share link if redirect url env variable set", @@ -1041,7 +1041,7 @@ func Test_shareObject(t *testing.T) { }, }, wantError: nil, - expected: "http://proxy-url.com:9012/console/subpath/api/v1/download-shared-object/aHR0cDovL3NvbWV1cmw=", + expected: "http://proxy-url.com:9012/console/subpath/api/v1/download-shared-object/http:%2F%2Fsomeurl", }, { test: "returns redirect url with share link if redirect url env variable set with trailing slash", @@ -1060,7 +1060,7 @@ func Test_shareObject(t *testing.T) { }, }, wantError: nil, - expected: "http://proxy-url.com:9012/console/subpath/api/v1/download-shared-object/aHR0cDovL3NvbWV1cmw=", + expected: "http://proxy-url.com:9012/console/subpath/api/v1/download-shared-object/http:%2F%2Fsomeurl", }, } @@ -1077,7 +1077,7 @@ func Test_shareObject(t *testing.T) { return } } else { - tAssert.Equal(*url, tt.expected) + tAssert.Equal(tt.expected, *url) } }) } diff --git a/api/utils.go b/api/utils.go index 3841b9b29..bff619b46 100644 --- a/api/utils.go +++ b/api/utils.go @@ -211,11 +211,6 @@ func ValidateEncodedStyles(encodedStyles string) error { return nil } -// SanitizeEncodedPrefix replaces spaces for + since those are lost when you do GET parameters -func SanitizeEncodedPrefix(rawPrefix string) string { - return strings.ReplaceAll(rawPrefix, " ", "+") -} - var safeMimeTypes = []string{ "image/jpeg", "image/apng", diff --git a/api/utils_test.go b/api/utils_test.go index 43a8c3613..45cbc514f 100644 --- a/api/utils_test.go +++ b/api/utils_test.go @@ -153,37 +153,6 @@ func TestExpireSessionCookie(t *testing.T) { } } -func TestSanitizeEncodedPrefix(t *testing.T) { - type args struct { - rawPrefix string - } - tests := []struct { - name string - args args - want string - }{ - { - name: "replace spaces with +", - args: args{ - rawPrefix: "hello world", - }, - want: "hello+world", - }, - { - name: "replace spaces with +", - args: args{ - rawPrefix: " hello-world ", - }, - want: "+++hello-world+++", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(_ *testing.T) { - assert.Equalf(t, tt.want, SanitizeEncodedPrefix(tt.args.rawPrefix), "SanitizeEncodedPrefix(%v)", tt.args.rawPrefix) - }) - } -} - func Test_isSafeToPreview(t *testing.T) { type args struct { str string @@ -293,27 +262,3 @@ func TestValidateEncodedStyles(t *testing.T) { }) } } - -func TestSanitizeEncodedPrefix1(t *testing.T) { - type args struct { - rawPrefix string - } - tests := []struct { - name string - args args - want string - }{ - { - name: "input sanitized", - args: args{ - rawPrefix: "x y", - }, - want: "x+y", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(_ *testing.T) { - assert.Equalf(t, tt.want, SanitizeEncodedPrefix(tt.args.rawPrefix), "SanitizeEncodedPrefix(%v)", tt.args.rawPrefix) - }) - } -} diff --git a/generator.config.js b/generator.config.js new file mode 100644 index 000000000..27c4e323c --- /dev/null +++ b/generator.config.js @@ -0,0 +1,5 @@ +module.exports = { + hooks: { + onInsertPathParam: (paramName) => `encodeURIComponent(${paramName})`, + }, +}; diff --git a/integration/buckets_test.go b/integration/buckets_test.go index d8cf01ce0..b9233e467 100644 --- a/integration/buckets_test.go +++ b/integration/buckets_test.go @@ -18,7 +18,6 @@ package integration import ( "bytes" - b64 "encoding/base64" "encoding/json" "fmt" "io" @@ -36,14 +35,6 @@ import ( var token string -func encodeBase64(fileName string) string { - /* - Helper function to encode in base64 the file name so we can get the path - */ - path := b64.StdEncoding.EncodeToString([]byte(fileName)) - return path -} - func inspectHTTPResponse(httpResponse *http.Response) string { /* Helper function to inspect the content of a HTTP response. diff --git a/integration/groups_test.go b/integration/groups_test.go index 6530f658e..0fba202e3 100644 --- a/integration/groups_test.go +++ b/integration/groups_test.go @@ -18,11 +18,11 @@ package integration import ( "bytes" - "encoding/base64" "encoding/json" "fmt" "log" "net/http" + "net/url" "testing" "time" @@ -114,7 +114,7 @@ func Test_GetGroupAPI(t *testing.T) { { name: "Get Group - Valid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("getgroup1")), + api: "getgroup1", }, expectedStatus: 200, expectedError: nil, @@ -122,7 +122,7 @@ func Test_GetGroupAPI(t *testing.T) { { name: "Get Group - Invalid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("askfjalkd")), + api: "askfjalkd", }, expectedStatus: 500, expectedError: nil, @@ -140,7 +140,7 @@ func Test_GetGroupAPI(t *testing.T) { requestDataJSON, _ := json.Marshal(requestDataPolicy) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - "GET", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody) + "GET", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", url.PathEscape(tt.args.api)), requestDataBody) if err != nil { log.Println(err) return @@ -224,7 +224,7 @@ func Test_PutGroupsAPI(t *testing.T) { { name: "Put Group - Valid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("putgroup1")), + api: "putgroup1", members: []string{"member3"}, status: "enabled", }, @@ -234,7 +234,7 @@ func Test_PutGroupsAPI(t *testing.T) { { name: "Put Group - Invalid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("gdgfdfgd")), + api: "gdgfdfgd", members: []string{"member3"}, status: "enabled", }, @@ -257,7 +257,7 @@ func Test_PutGroupsAPI(t *testing.T) { requestDataJSON, _ := json.Marshal(requestDataPolicy) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - "PUT", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody) + "PUT", fmt.Sprintf("http://localhost:9090/api/v1/group/%s", url.PathEscape(tt.args.api)), requestDataBody) if err != nil { log.Println(err) return @@ -294,7 +294,7 @@ func Test_DeleteGroupAPI(t *testing.T) { { name: "Delete Group - Valid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("grouptests1")), + api: "grouptests1", }, verb: "DELETE", expectedStatus: 204, @@ -303,7 +303,7 @@ func Test_DeleteGroupAPI(t *testing.T) { { name: "Delete Group - Invalid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("grouptests12345")), + api: "grouptests12345", }, verb: "DELETE", expectedStatus: 404, @@ -312,7 +312,7 @@ func Test_DeleteGroupAPI(t *testing.T) { { name: "Access Group After Delete - Invalid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("grouptests1")), + api: "grouptests1", }, verb: "GET", expectedStatus: 500, @@ -331,7 +331,7 @@ func Test_DeleteGroupAPI(t *testing.T) { requestDataJSON, _ := json.Marshal(requestDataPolicy) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - tt.verb, fmt.Sprintf("http://localhost:9090/api/v1/group/%s", tt.args.api), requestDataBody) + tt.verb, fmt.Sprintf("http://localhost:9090/api/v1/group/%s", url.PathEscape(tt.args.api)), requestDataBody) if err != nil { log.Println(err) return diff --git a/integration/objects_test.go b/integration/objects_test.go index 2c304bbe3..7ae3836b1 100644 --- a/integration/objects_test.go +++ b/integration/objects_test.go @@ -19,12 +19,12 @@ package integration import ( "bytes" "context" - "encoding/base64" "encoding/json" "fmt" "log" "math/rand" "net/http" + "net/url" "strings" "testing" "time" @@ -90,7 +90,7 @@ func TestObjectGet(t *testing.T) { { name: "Preview Object", args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject")), + encodedPrefix: "myobject", }, expectedStatus: 200, expectedError: nil, @@ -98,7 +98,7 @@ func TestObjectGet(t *testing.T) { { name: "Preview image", args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")), + encodedPrefix: "myobject.jpg", }, expectedStatus: 200, expectedError: nil, @@ -106,7 +106,7 @@ func TestObjectGet(t *testing.T) { { name: "Get Range of bytes", args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")), + encodedPrefix: "myobject.jpg", bytesRange: "bytes=1-4", }, expectedStatus: 206, @@ -115,7 +115,7 @@ func TestObjectGet(t *testing.T) { { name: "Get Range of bytes empty start", args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")), + encodedPrefix: "myobject.jpg", bytesRange: "bytes=-4", }, expectedStatus: 206, @@ -124,7 +124,7 @@ func TestObjectGet(t *testing.T) { { name: "Get Invalid Range of bytes", args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")), + encodedPrefix: "myobject.jpg", bytesRange: "bytes=9-12", }, expectedStatus: 500, @@ -133,7 +133,7 @@ func TestObjectGet(t *testing.T) { { name: "Get Larger Range of bytes empty start", args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")), + encodedPrefix: "myobject.jpg", bytesRange: "bytes=-12", }, expectedStatus: 206, @@ -142,29 +142,12 @@ func TestObjectGet(t *testing.T) { { name: "Get invalid seek start Range of bytes", args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject.jpg")), + encodedPrefix: "myobject.jpg", bytesRange: "bytes=12-16", }, expectedStatus: 500, expectedError: nil, }, - { - name: "Bad Preview Object", - args: args{ - encodedPrefix: "garble", - }, - expectedStatus: 400, - expectedError: nil, - }, - { - name: "Bad Version Preview Object", - args: args{ - encodedPrefix: base64.StdEncoding.EncodeToString([]byte("myobject")), - versionID: "garble", - }, - expectedStatus: 500, - expectedError: nil, - }, } for _, tt := range tests { @@ -172,7 +155,7 @@ func TestObjectGet(t *testing.T) { client := &http.Client{ Timeout: 3 * time.Second, } - destination := fmt.Sprintf("/api/v1/buckets/%s/objects/download?preview=true&prefix=%s&version_id=%s", bucketName, tt.args.encodedPrefix, tt.args.versionID) + destination := fmt.Sprintf("/api/v1/buckets/%s/objects/download?preview=true&prefix=%s&version_id=%s", url.PathEscape(bucketName), url.QueryEscape(tt.args.encodedPrefix), url.QueryEscape(tt.args.versionID)) finalURL := fmt.Sprintf("http://localhost:9090%s", destination) request, err := http.NewRequest("GET", finalURL, nil) if err != nil { @@ -198,7 +181,7 @@ func TestObjectGet(t *testing.T) { } func downloadMultipleFiles(bucketName string, objects []string) (*http.Response, error) { - requestURL := fmt.Sprintf("http://localhost:9090/api/v1/buckets/%s/objects/download-multiple", bucketName) + requestURL := fmt.Sprintf("http://localhost:9090/api/v1/buckets/%s/objects/download-multiple", url.PathEscape(bucketName)) postReqParams, _ := json.Marshal(objects) reqBody := bytes.NewReader(postReqParams) diff --git a/integration/policy_test.go b/integration/policy_test.go index 95da7f5c2..62cdf2a1b 100644 --- a/integration/policy_test.go +++ b/integration/policy_test.go @@ -18,12 +18,12 @@ package integration import ( "bytes" - "encoding/base64" "encoding/json" "fmt" "io" "log" "net/http" + "net/url" "testing" "time" @@ -179,6 +179,31 @@ func Test_AddPolicyAPI(t *testing.T) { expectedStatus: 400, expectedError: nil, }, + { + name: "Create Policy - Reserved character in name", + args: args{ + api: "/policies", + name: "space/test?", + policy: swag.String(` + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:GetBucketLocation", + "s3:GetObject" + ], + "Resource": [ + "arn:aws:s3:::*" + ] + } + ] +}`), + }, + expectedStatus: 201, + expectedError: nil, + }, } for _, tt := range tests { @@ -491,7 +516,7 @@ func Test_ListPoliciesAPI(t *testing.T) { func Test_GetPolicyAPI(t *testing.T) { assert := assert.New(t) - AddPolicy("getpolicytest", ` + AddPolicy("test/policy?", ` { "Version": "2012-10-17", "Statement": [ @@ -520,7 +545,7 @@ func Test_GetPolicyAPI(t *testing.T) { { name: "Get Policies - Invalid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("test3")), + api: "test3", }, expectedStatus: 500, expectedError: nil, @@ -528,7 +553,7 @@ func Test_GetPolicyAPI(t *testing.T) { { name: "Get Policies - Valid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("getpolicytest")), + api: "test/policy?", }, expectedStatus: 200, expectedError: nil, @@ -542,7 +567,7 @@ func Test_GetPolicyAPI(t *testing.T) { } request, err := http.NewRequest( - "GET", fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", tt.args.api), nil) + "GET", fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", url.PathEscape(tt.args.api)), nil) if err != nil { log.Println(err) return @@ -595,7 +620,7 @@ func Test_PolicyListUsersAPI(t *testing.T) { { name: "List Users for Policy - Valid", args: args{ - api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("policylistusers")) + "/users", + api: "/policies/" + url.PathEscape("policylistusers") + "/users", }, expectedStatus: 200, expectedError: nil, @@ -603,7 +628,7 @@ func Test_PolicyListUsersAPI(t *testing.T) { { name: "List Users for Policy - Invalid", args: args{ - api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("test2")) + "/users", + api: "/policies/" + url.PathEscape("test2") + "/users", }, expectedStatus: 404, expectedError: nil, @@ -674,7 +699,7 @@ func Test_PolicyListGroupsAPI(t *testing.T) { { name: "List Users for Policy - Valid", args: args{ - api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("policylistgroups")) + "/groups", + api: "/policies/" + url.PathEscape("policylistgroups") + "/groups", }, expectedStatus: 200, expectedError: nil, @@ -682,7 +707,7 @@ func Test_PolicyListGroupsAPI(t *testing.T) { { name: "List Users for Policy - Invalid", args: args{ - api: "/policies/" + base64.StdEncoding.EncodeToString([]byte("test3")) + "/groups", + api: "/policies/" + url.PathEscape("test3") + "/groups", }, expectedStatus: 404, expectedError: nil, @@ -751,7 +776,7 @@ func Test_DeletePolicyAPI(t *testing.T) { { name: "Delete Policies - Valid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("testdelete")), + api: "testdelete", method: "DELETE", }, expectedStatus: 204, @@ -760,7 +785,7 @@ func Test_DeletePolicyAPI(t *testing.T) { { name: "Get Policy After Delete - Invalid", args: args{ - api: base64.StdEncoding.EncodeToString([]byte("testdelete")), + api: "testdelete", method: "GET", }, expectedStatus: 500, @@ -775,7 +800,7 @@ func Test_DeletePolicyAPI(t *testing.T) { } request, err := http.NewRequest( - tt.args.method, fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", tt.args.api), nil) + tt.args.method, fmt.Sprintf("http://localhost:9090/api/v1/policy/%s", url.PathEscape(tt.args.api)), nil) if err != nil { log.Println(err) return @@ -804,11 +829,6 @@ func Test_GetAUserPolicyAPI(t *testing.T) { log.Println(err) return } - // encode usernames to pass to api - bName := []byte("getuserpolicyuser") - fName := []byte("failname") - encodedName := base64.URLEncoding.EncodeToString(bName) - encodedFailName := base64.URLEncoding.EncodeToString(fName) type args struct { api string @@ -822,7 +842,7 @@ func Test_GetAUserPolicyAPI(t *testing.T) { { name: "Get User Policy - Invalid", args: args{ - api: "/user/" + encodedFailName + "/policies", + api: "/user/" + url.PathEscape("failname") + "/policies", }, expectedStatus: 401, expectedError: nil, @@ -830,7 +850,7 @@ func Test_GetAUserPolicyAPI(t *testing.T) { { name: "Get User Policy - Valid", args: args{ - api: "/user/" + encodedName + "/policies", + api: "/user/" + url.PathEscape("getuserpolicyuser") + "/policies", }, expectedStatus: 200, expectedError: nil, diff --git a/integration/service_account_test.go b/integration/service_account_test.go index b8c22a43a..ce6ee4690 100644 --- a/integration/service_account_test.go +++ b/integration/service_account_test.go @@ -18,11 +18,11 @@ package integration import ( "bytes" - "encoding/base64" "encoding/json" "fmt" "log" "net/http" + "net/url" "testing" "time" @@ -92,7 +92,7 @@ func TestAddServiceAccount(t *testing.T) { // {{baseUrl}}/user?name=proident velit // Investiga como se borra en el browser. request, err = http.NewRequest( - "DELETE", "http://localhost:9090/api/v1/service-accounts/"+base64.StdEncoding.EncodeToString([]byte("testuser1")), nil) + "DELETE", "http://localhost:9090/api/v1/service-accounts/"+url.PathEscape("testuser1"), nil) if err != nil { log.Println(err) return diff --git a/integration/user_api_bucket_test.go b/integration/user_api_bucket_test.go index ebf2c93f9..0523a1ebf 100644 --- a/integration/user_api_bucket_test.go +++ b/integration/user_api_bucket_test.go @@ -21,13 +21,13 @@ package integration import ( "bytes" "context" - "encoding/base64" "encoding/json" "errors" "fmt" "io" "log" "net/http" + "net/url" "os" "strconv" "strings" @@ -396,7 +396,7 @@ func UploadAnObject(bucketName, fileName string) (*http.Response, error) { contentType + boundaryEnd arrayOfBytes := []byte(file) requestDataBody := bytes.NewReader(arrayOfBytes) - apiURL := "http://localhost:9090/api/v1/buckets/" + bucketName + "/objects/upload" + "?prefix=" + base64.StdEncoding.EncodeToString([]byte(fileName)) + apiURL := "http://localhost:9090/api/v1/buckets/" + url.PathEscape(bucketName) + "/objects/upload" + "?prefix=" + url.QueryEscape(fileName) request, err := http.NewRequest( "POST", apiURL, @@ -423,9 +423,8 @@ func DeleteObject(bucketName, path string, recursive, allVersions bool) (*http.R DELETE: {{baseUrl}}/buckets/bucketName/objects?path=Y2VzYXJpby50eHQ=&recursive=false&all_versions=false */ - prefixEncoded := base64.StdEncoding.EncodeToString([]byte(path)) - url := "http://localhost:9090/api/v1/buckets/" + bucketName + "/objects?prefix=" + - prefixEncoded + "&recursive=" + strconv.FormatBool(recursive) + "&all_versions=" + + url := "http://localhost:9090/api/v1/buckets/" + url.PathEscape(bucketName) + "/objects?prefix=" + + url.QueryEscape(path) + "&recursive=" + strconv.FormatBool(recursive) + "&all_versions=" + strconv.FormatBool(allVersions) request, err := http.NewRequest( "DELETE", @@ -444,13 +443,13 @@ func DeleteObject(bucketName, path string, recursive, allVersions bool) (*http.R return response, err } -func ListObjects(bucketName, prefix, withVersions string) (*http.Response, error) { +func ListObjects(bucketName, prefix string, withVersions bool) (*http.Response, error) { /* Helper function to list objects in a bucket. GET: {{baseUrl}}/buckets/:bucket_name/objects */ request, err := http.NewRequest("GET", - "http://localhost:9090/api/v1/buckets/"+bucketName+"/objects?prefix="+prefix+"&with_versions="+withVersions, + "http://localhost:9090/api/v1/buckets/"+url.PathEscape(bucketName)+"/objects?prefix="+url.QueryEscape(prefix)+"&with_versions="+strconv.FormatBool(withVersions), nil) if err != nil { log.Println(err) @@ -753,8 +752,8 @@ func TestPutObjectsLegalholdStatus(t *testing.T) { // Variables assert := assert.New(t) bucketName := "testputobjectslegalholdstatus" - objName := "testputobjectslegalholdstatus.txt" // // encoded base64 of testputobjectslegalholdstatus.txt = dGVzdHB1dG9iamVjdHNsZWdhbGhvbGRzdGF0dXMudHh0 - objectNameEncoded := "dGVzdHB1dG9iamVjdHNsZWdhbGhvbGRzdGF0dXMudHh0" + objName := "testputobjectslegalholdstatus.txt" + objectNameEncoded := url.QueryEscape(objName) status := "enabled" // 1. Create bucket @@ -782,7 +781,7 @@ func TestPutObjectsLegalholdStatus(t *testing.T) { } // Get versionID - listResponse, _ := ListObjects(bucketName, "", "true") + listResponse, _ := ListObjects(bucketName, "", true) bodyBytes, _ := io.ReadAll(listResponse.Body) listObjs := models.ListObjectsResponse{} err := json.Unmarshal(bodyBytes, &listObjs) @@ -807,13 +806,6 @@ func TestPutObjectsLegalholdStatus(t *testing.T) { versionID: validVersionID, }, }, - { - name: "Invalid VersionID when putting object's legal hold status", - expectedStatus: 500, - args: args{ - versionID: "*&^###Test1ThisMightBeInvalid555", - }, - }, } for _, tt := range tests { t.Run(tt.name, func(_ *testing.T) { @@ -1036,7 +1028,7 @@ func TestDeleteObjectsRetentionStatus(t *testing.T) { assert := assert.New(t) bucketName := "testdeleteobjectslegalholdstatus" fileName := "testdeleteobjectslegalholdstatus.txt" - validPrefix := encodeBase64(fileName) + validPrefix := url.QueryEscape(fileName) // 1. Create bucket if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) { @@ -1063,7 +1055,7 @@ func TestDeleteObjectsRetentionStatus(t *testing.T) { } // Get versionID - listResponse, _ := ListObjects(bucketName, validPrefix, "true") + listResponse, _ := ListObjects(bucketName, validPrefix, true) bodyBytes, _ := io.ReadAll(listResponse.Body) listObjs := models.ListObjectsResponse{} err := json.Unmarshal(bodyBytes, &listObjs) @@ -1204,7 +1196,7 @@ func TestRestoreObjectToASelectedVersion(t *testing.T) { assert := assert.New(t) bucketName := "testrestoreobjectstoselectedversion" fileName := "testrestoreobjectstoselectedversion.txt" - validPrefix := encodeBase64(fileName) + validPrefix := url.QueryEscape(fileName) // 1. Create bucket if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) { @@ -1231,7 +1223,7 @@ func TestRestoreObjectToASelectedVersion(t *testing.T) { } // 3. Get versionID - listResponse, _ := ListObjects(bucketName, validPrefix, "true") + listResponse, _ := ListObjects(bucketName, validPrefix, true) bodyBytes, _ := io.ReadAll(listResponse.Body) listObjs := models.ListObjectsResponse{} err := json.Unmarshal(bodyBytes, &listObjs) @@ -1348,7 +1340,7 @@ func TestGetsTheMetadataOfAnObject(t *testing.T) { assert := assert.New(t) bucketName := "testgetsthemetadataofanobject" fileName := "testshareobjectonurl.txt" - validPrefix := encodeBase64(fileName) + validPrefix := url.QueryEscape(fileName) tags := make(map[string]string) tags["tag"] = "testputobjecttagbucketonetagone" @@ -1421,7 +1413,7 @@ func TestPutObjectsRetentionStatus(t *testing.T) { assert := assert.New(t) bucketName := "testputobjectsretentionstatus" fileName := "testputobjectsretentionstatus.txt" - prefix := encodeBase64(fileName) + prefix := url.QueryEscape(fileName) // 1. Create bucket if !setupBucket(bucketName, true, map[string]interface{}{"enabled": true}, nil, nil, assert, 200) { @@ -1448,7 +1440,7 @@ func TestPutObjectsRetentionStatus(t *testing.T) { } // Get versionID - listResponse, _ := ListObjects(bucketName, prefix, "true") + listResponse, _ := ListObjects(bucketName, prefix, true) bodyBytes, _ := io.ReadAll(listResponse.Body) listObjs := models.ListObjectsResponse{} err := json.Unmarshal(bodyBytes, &listObjs) @@ -1470,14 +1462,7 @@ func TestPutObjectsRetentionStatus(t *testing.T) { name: "Valid VersionID when putting object's retention status", expectedStatus: 200, args: args{ - versionID: validVersionID, - }, - }, - { - name: "Invalid VersionID when putting object's retention status", - expectedStatus: 500, - args: args{ - versionID: "*&^###Test1ThisMightBeInvalid555", + versionID: url.QueryEscape(validVersionID), }, }, } @@ -1516,7 +1501,7 @@ func TestShareObjectOnURL(t *testing.T) { assert := assert.New(t) bucketName := "testshareobjectonurl" fileName := "testshareobjectonurl.txt" - validPrefix := encodeBase64(fileName) + validPrefix := url.QueryEscape(fileName) tags := make(map[string]string) tags["tag"] = "testputobjecttagbucketonetagone" versionID := "null" @@ -1556,13 +1541,6 @@ func TestShareObjectOnURL(t *testing.T) { prefix: validPrefix, }, }, - { - name: "Share file with invalid prefix", - expectedStatus: 500, - args: args{ - prefix: "invalidprefix", - }, - }, } for _, tt := range tests { t.Run(tt.name, func(_ *testing.T) { @@ -1613,7 +1591,7 @@ func TestListObjects(t *testing.T) { } // 3. List the object - listResponse, listError := ListObjects(bucketName, "", "false") + listResponse, listError := ListObjects(bucketName, "", false) assert.Nil(listError) if listError != nil { log.Println(listError) @@ -1676,7 +1654,7 @@ func TestDeleteObject(t *testing.T) { } // 4. List the objects in the bucket and make sure the object is gone - listResponse, listError := ListObjects(bucketName, "", "false") + listResponse, listError := ListObjects(bucketName, "", false) assert.Nil(listError) if listError != nil { log.Println(listError) @@ -1738,7 +1716,7 @@ func TestDownloadObject(t *testing.T) { assert := assert.New(t) bucketName := "testdownloadobjbucketone" fileName := "testdownloadobjectfilenameone" - path := encodeBase64(fileName) + path := url.QueryEscape(fileName) workingDirectory, getWdErr := os.Getwd() if getWdErr != nil { assert.Fail("Couldn't get the directory") @@ -1852,7 +1830,7 @@ func TestDeleteMultipleObjects(t *testing.T) { } // 4. List the objects, empty list is expected! - listResponse, listError := ListObjects(bucketName, "", "false") + listResponse, listError := ListObjects(bucketName, "", false) assert.Nil(listError) if listError != nil { log.Println(listError) @@ -1878,7 +1856,7 @@ func TestPutObjectTag(t *testing.T) { assert := assert.New(t) bucketName := "testputobjecttagbucketone" fileName := "testputobjecttagbucketone.txt" - path := encodeBase64(fileName) + path := url.QueryEscape(fileName) tags := make(map[string]string) tags["tag"] = "testputobjecttagbucketonetagone" versionID := "null" @@ -1918,7 +1896,7 @@ func TestPutObjectTag(t *testing.T) { } // 4. Verify the object's tag is set - listResponse, listError := ListObjects(bucketName, path, "false") + listResponse, listError := ListObjects(bucketName, path, false) assert.Nil(listError) if listError != nil { log.Println(listError) diff --git a/integration/users_test.go b/integration/users_test.go index 86c321b03..2b7df9db0 100644 --- a/integration/users_test.go +++ b/integration/users_test.go @@ -18,12 +18,12 @@ package integration import ( "bytes" - "encoding/base64" "encoding/json" "fmt" "io" "log" "net/http" + "net/url" "strconv" "strings" "testing" @@ -63,7 +63,6 @@ func AddUser(accessKey, secretKey string, groups, policies []string) (*http.Resp } func DeleteUser(userName string) (*http.Response, error) { - userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* This is an atomic function to delete user and can be reused across different functions. @@ -72,7 +71,7 @@ func DeleteUser(userName string) (*http.Response, error) { Timeout: 3 * time.Second, } request, err := http.NewRequest( - "DELETE", "http://localhost:9090/api/v1/user/"+userName, nil) + "DELETE", "http://localhost:9090/api/v1/user/"+url.PathEscape(userName), nil) if err != nil { log.Println(err) } @@ -104,7 +103,6 @@ func ListUsers(offset, limit string) (*http.Response, error) { } func GetUserInformation(userName string) (*http.Response, error) { - userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to get user information via API: {{baseUrl}}/user?name=proident velit @@ -114,7 +112,7 @@ func GetUserInformation(userName string) (*http.Response, error) { } request, err := http.NewRequest( "GET", - "http://localhost:9090/api/v1/user/"+userName, + "http://localhost:9090/api/v1/user/"+url.PathEscape(userName), nil) if err != nil { log.Println(err) @@ -126,7 +124,6 @@ func GetUserInformation(userName string) (*http.Response, error) { } func UpdateUserInformation(name, status string, groups []string) (*http.Response, error) { - name = base64.StdEncoding.EncodeToString([]byte(name)) /* Helper function to update user information: PUT: {{baseUrl}}/user?name=proident velit @@ -149,7 +146,7 @@ func UpdateUserInformation(name, status string, groups []string) (*http.Response requestDataJSON, _ := json.Marshal(requestDataAdd) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( - "PUT", "http://localhost:9090/api/v1/user/"+name, requestDataBody) + "PUT", "http://localhost:9090/api/v1/user/"+url.PathEscape(name), requestDataBody) if err != nil { log.Println(err) } @@ -160,7 +157,6 @@ func UpdateUserInformation(name, status string, groups []string) (*http.Response } func RemoveUser(name string) (*http.Response, error) { - name = base64.StdEncoding.EncodeToString([]byte(name)) /* Helper function to remove user. DELETE: {{baseUrl}}/user?name=proident velit @@ -169,7 +165,7 @@ func RemoveUser(name string) (*http.Response, error) { Timeout: 3 * time.Second, } request, err := http.NewRequest( - "DELETE", "http://localhost:9090/api/v1/user/"+name, nil) + "DELETE", "http://localhost:9090/api/v1/user/"+url.PathEscape(name), nil) if err != nil { log.Println(err) } @@ -180,7 +176,6 @@ func RemoveUser(name string) (*http.Response, error) { } func UpdateGroupsForAUser(userName string, groups []string) (*http.Response, error) { - userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to update groups for a user PUT: {{baseUrl}}/user/groups?name=username @@ -201,7 +196,7 @@ func UpdateGroupsForAUser(userName string, groups []string) (*http.Response, err requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( "PUT", - "http://localhost:9090/api/v1/user/"+userName+"/groups", + "http://localhost:9090/api/v1/user/"+url.PathEscape(userName)+"/groups", requestDataBody, ) if err != nil { @@ -214,7 +209,6 @@ func UpdateGroupsForAUser(userName string, groups []string) (*http.Response, err } func CreateServiceAccountForUser(userName, policy string) (*http.Response, error) { - userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to Create Service Account for user POST: api/v1/user/username/service-accounts @@ -232,7 +226,7 @@ func CreateServiceAccountForUser(userName, policy string) (*http.Response, error requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( "POST", - "http://localhost:9090/api/v1/user/"+userName+"/service-accounts", + "http://localhost:9090/api/v1/user/"+url.PathEscape(userName)+"/service-accounts", requestDataBody, ) if err != nil { @@ -245,7 +239,6 @@ func CreateServiceAccountForUser(userName, policy string) (*http.Response, error } func CreateServiceAccountForUserWithCredentials(userName, policy, accessKey, secretKey string) (*http.Response, error) { - userName = base64.StdEncoding.EncodeToString([]byte(userName)) // Helper function to test "Create Service Account for User With Credentials" end point. client := &http.Client{ Timeout: 3 * time.Second, @@ -259,7 +252,7 @@ func CreateServiceAccountForUserWithCredentials(userName, policy, accessKey, sec requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( "POST", - "http://localhost:9090/api/v1/user/"+userName+"/service-account-credentials", + "http://localhost:9090/api/v1/user/"+url.PathEscape(userName)+"/service-account-credentials", requestDataBody, ) if err != nil { @@ -272,7 +265,6 @@ func CreateServiceAccountForUserWithCredentials(userName, policy, accessKey, sec } func ReturnsAListOfServiceAccountsForAUser(userName string) (*http.Response, error) { - userName = base64.StdEncoding.EncodeToString([]byte(userName)) /* Helper function to return a list of service accounts for a user. GET: {{baseUrl}}/user/:name/service-accounts @@ -282,7 +274,7 @@ func ReturnsAListOfServiceAccountsForAUser(userName string) (*http.Response, err } request, err := http.NewRequest( "GET", - "http://localhost:9090/api/v1/user/"+userName+"/service-accounts", + "http://localhost:9090/api/v1/user/"+url.PathEscape(userName)+"/service-accounts", nil, ) if err != nil { diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index d7b3e828e..48e36010f 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -18,18 +18,8 @@ package utils import ( "context" - "encoding/base64" ) -// DecodeBase64 : decoded base64 input into utf-8 text -func DecodeBase64(s string) (string, error) { - decodedInput, err := base64.StdEncoding.DecodeString(s) - if err != nil { - return "", err - } - return string(decodedInput), nil -} - // Key used for Get/SetReqInfo type key string diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 2fa54cf9d..168774dd3 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -18,6 +18,7 @@ package utils import ( "context" + "net/url" "testing" ) @@ -34,7 +35,7 @@ func TestDecodeInput(t *testing.T) { { name: "chinese characters", args: args{ - s: "5bCP6aO85by+5bCP6aO85by+5bCP6aO85by+L+Wwj+mjvOW8vuWwj+mjvOW8vuWwj+mjvOW8vg==", + s: "%E5%B0%8F%E9%A3%BC%E5%BC%BE%E5%B0%8F%E9%A3%BC%E5%BC%BE%E5%B0%8F%E9%A3%BC%E5%BC%BE%2F%E5%B0%8F%E9%A3%BC%E5%BC%BE%E5%B0%8F%E9%A3%BC%E5%BC%BE%E5%B0%8F%E9%A3%BC%E5%BC%BE", }, want: "小飼弾小飼弾小飼弾/小飼弾小飼弾小飼弾", wantErr: false, @@ -42,7 +43,7 @@ func TestDecodeInput(t *testing.T) { { name: "spaces and & symbol", args: args{ - s: "YSBhIC0gYSBhICYgYSBhIC0gYSBhIGE=", + s: "a%20a%20-%20a%20a%20%26%20a%20a%20-%20a%20a%20a", }, want: "a a - a a & a a - a a a", wantErr: false, @@ -50,7 +51,7 @@ func TestDecodeInput(t *testing.T) { { name: "the infamous fly me to the moon", args: args{ - s: "MDIlMjAtJTIwRkxZJTIwTUUlMjBUTyUyMFRIRSUyME1PT04lMjA=", + s: "02%2520-%2520FLY%2520ME%2520TO%2520THE%2520MOON%2520", }, want: "02%20-%20FLY%20ME%20TO%20THE%20MOON%20", wantErr: false, @@ -58,7 +59,7 @@ func TestDecodeInput(t *testing.T) { { name: "random symbols", args: args{ - s: "IUAjJCVeJiooKV8r", + s: "!%40%23%24%25%5E%26*()_%2B", }, want: "!@#$%^&*()_+", wantErr: false, @@ -66,7 +67,7 @@ func TestDecodeInput(t *testing.T) { { name: "name with / symbols", args: args{ - s: "dGVzdC90ZXN0Mi/lsI/po7zlvL7lsI/po7zlvL7lsI/po7zlvL4uanBn", + s: "test%2Ftest2%2F%E5%B0%8F%E9%A3%BC%E5%BC%BE%E5%B0%8F%E9%A3%BC%E5%BC%BE%E5%B0%8F%E9%A3%BC%E5%BC%BE.jpg", }, want: "test/test2/小飼弾小飼弾小飼弾.jpg", wantErr: false, @@ -74,7 +75,7 @@ func TestDecodeInput(t *testing.T) { { name: "decoding fails", args: args{ - s: "this should fail", + s: "%%this should fail%%", }, want: "", wantErr: true, @@ -82,7 +83,7 @@ func TestDecodeInput(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(_ *testing.T) { - got, err := DecodeBase64(tt.args.s) + got, err := url.QueryUnescape(tt.args.s) if (err != nil) != tt.wantErr { t.Errorf("DecodeBase64() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/semgrep.yaml b/semgrep.yaml index b470c90ea..cf6dc326a 100644 --- a/semgrep.yaml +++ b/semgrep.yaml @@ -1,26 +1,13 @@ rules: - - id: js-func-encode-uri-Component - patterns: - - pattern: encodeURIComponent($X) - - pattern-not-inside: | - export const encodeURLString = (...) => { - ... - }; - message: Use encodeURLString() instead of encodeURIComponent() - languages: - - typescript - - javascript - severity: WARNING - fix: encodeURLString($X) - id: js-func-encode-uri patterns: - pattern: encodeURI($X) - message: Use encodeURLString() instead of encodeURI() + message: Use encodeURIComponent() instead of encodeURI() languages: - typescript - javascript severity: WARNING - fix: encodeURLString($X) + fix: encodeURIComponent($X) - id: js-dangerous-func-document-write patterns: - pattern: document.write(...) diff --git a/web-app/src/api/consoleApi.ts b/web-app/src/api/consoleApi.ts index 49f733874..5c9c5d63b 100644 --- a/web-app/src/api/consoleApi.ts +++ b/web-app/src/api/consoleApi.ts @@ -1987,7 +1987,7 @@ export class Api< */ bucketInfo: (name: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${name}`, + path: `/buckets/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -2005,7 +2005,7 @@ export class Api< */ deleteBucket: (name: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${name}`, + path: `/buckets/${encodeURIComponent(name)}`, method: "DELETE", secure: true, ...params, @@ -2025,7 +2025,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/retention`, + path: `/buckets/${encodeURIComponent(bucketName)}/retention`, method: "GET", secure: true, format: "json", @@ -2047,7 +2047,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/retention`, + path: `/buckets/${encodeURIComponent(bucketName)}/retention`, method: "PUT", body: body, secure: true, @@ -2080,7 +2080,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects`, method: "GET", query: query, secure: true, @@ -2110,7 +2110,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects`, method: "DELETE", query: query, secure: true, @@ -2136,7 +2136,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/delete-objects`, + path: `/buckets/${encodeURIComponent(bucketName)}/delete-objects`, method: "POST", query: query, body: files, @@ -2163,7 +2163,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/upload`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/upload`, method: "POST", query: query, body: data, @@ -2187,7 +2187,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/download-multiple`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/download-multiple`, method: "POST", body: objectList, secure: true, @@ -2217,7 +2217,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/download`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/download`, method: "GET", query: query, secure: true, @@ -2243,7 +2243,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/share`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/share`, method: "GET", query: query, secure: true, @@ -2270,7 +2270,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/legalhold`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/legalhold`, method: "PUT", query: query, body: body, @@ -2298,7 +2298,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/retention`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/retention`, method: "PUT", query: query, body: body, @@ -2325,7 +2325,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/retention`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/retention`, method: "DELETE", query: query, secure: true, @@ -2351,7 +2351,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/tags`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/tags`, method: "PUT", query: query, body: body, @@ -2378,7 +2378,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/restore`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/restore`, method: "PUT", query: query, secure: true, @@ -2403,7 +2403,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/objects/metadata`, + path: `/buckets/${encodeURIComponent(bucketName)}/objects/metadata`, method: "GET", query: query, secure: true, @@ -2426,7 +2426,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/tags`, + path: `/buckets/${encodeURIComponent(bucketName)}/tags`, method: "PUT", body: body, secure: true, @@ -2449,7 +2449,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${name}/set-policy`, + path: `/buckets/${encodeURIComponent(name)}/set-policy`, method: "PUT", body: body, secure: true, @@ -2469,7 +2469,7 @@ export class Api< */ getBucketQuota: (name: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${name}/quota`, + path: `/buckets/${encodeURIComponent(name)}/quota`, method: "GET", secure: true, format: "json", @@ -2491,7 +2491,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${name}/quota`, + path: `/buckets/${encodeURIComponent(name)}/quota`, method: "PUT", body: body, secure: true, @@ -2526,7 +2526,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/events`, + path: `/buckets/${encodeURIComponent(bucketName)}/events`, method: "GET", query: query, secure: true, @@ -2549,7 +2549,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/events`, + path: `/buckets/${encodeURIComponent(bucketName)}/events`, method: "POST", body: body, secure: true, @@ -2573,7 +2573,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/events/${arn}`, + path: `/buckets/${encodeURIComponent(bucketName)}/events/${encodeURIComponent(arn)}`, method: "DELETE", body: body, secure: true, @@ -2592,7 +2592,7 @@ export class Api< */ getBucketReplication: (bucketName: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${bucketName}/replication`, + path: `/buckets/${encodeURIComponent(bucketName)}/replication`, method: "GET", secure: true, format: "json", @@ -2614,7 +2614,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/replication/${ruleId}`, + path: `/buckets/${encodeURIComponent(bucketName)}/replication/${encodeURIComponent(ruleId)}`, method: "GET", secure: true, format: "json", @@ -2637,7 +2637,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/replication/${ruleId}`, + path: `/buckets/${encodeURIComponent(bucketName)}/replication/${encodeURIComponent(ruleId)}`, method: "PUT", body: body, secure: true, @@ -2660,7 +2660,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/replication/${ruleId}`, + path: `/buckets/${encodeURIComponent(bucketName)}/replication/${encodeURIComponent(ruleId)}`, method: "DELETE", secure: true, ...params, @@ -2680,7 +2680,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/delete-all-replication-rules`, + path: `/buckets/${encodeURIComponent(bucketName)}/delete-all-replication-rules`, method: "DELETE", secure: true, ...params, @@ -2701,7 +2701,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/delete-selected-replication-rules`, + path: `/buckets/${encodeURIComponent(bucketName)}/delete-selected-replication-rules`, method: "DELETE", body: rules, secure: true, @@ -2720,7 +2720,7 @@ export class Api< */ getBucketVersioning: (bucketName: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${bucketName}/versioning`, + path: `/buckets/${encodeURIComponent(bucketName)}/versioning`, method: "GET", secure: true, format: "json", @@ -2742,7 +2742,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/versioning`, + path: `/buckets/${encodeURIComponent(bucketName)}/versioning`, method: "PUT", body: body, secure: true, @@ -2764,7 +2764,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/object-locking`, + path: `/buckets/${encodeURIComponent(bucketName)}/object-locking`, method: "GET", secure: true, format: "json", @@ -2786,7 +2786,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/encryption/enable`, + path: `/buckets/${encodeURIComponent(bucketName)}/encryption/enable`, method: "POST", body: body, secure: true, @@ -2805,7 +2805,7 @@ export class Api< */ disableBucketEncryption: (bucketName: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${bucketName}/encryption/disable`, + path: `/buckets/${encodeURIComponent(bucketName)}/encryption/disable`, method: "POST", secure: true, ...params, @@ -2822,7 +2822,7 @@ export class Api< */ getBucketEncryptionInfo: (bucketName: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${bucketName}/encryption/info`, + path: `/buckets/${encodeURIComponent(bucketName)}/encryption/info`, method: "GET", secure: true, format: "json", @@ -2840,7 +2840,7 @@ export class Api< */ getBucketLifecycle: (bucketName: string, params: RequestParams = {}) => this.request({ - path: `/buckets/${bucketName}/lifecycle`, + path: `/buckets/${encodeURIComponent(bucketName)}/lifecycle`, method: "GET", secure: true, format: "json", @@ -2862,7 +2862,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/lifecycle`, + path: `/buckets/${encodeURIComponent(bucketName)}/lifecycle`, method: "POST", body: body, secure: true, @@ -2909,7 +2909,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/lifecycle/${lifecycleId}`, + path: `/buckets/${encodeURIComponent(bucketName)}/lifecycle/${encodeURIComponent(lifecycleId)}`, method: "PUT", body: body, secure: true, @@ -2932,7 +2932,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/lifecycle/${lifecycleId}`, + path: `/buckets/${encodeURIComponent(bucketName)}/lifecycle/${encodeURIComponent(lifecycleId)}`, method: "DELETE", secure: true, ...params, @@ -2956,7 +2956,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/buckets/${bucketName}/rewind/${date}`, + path: `/buckets/${encodeURIComponent(bucketName)}/rewind/${encodeURIComponent(date)}`, method: "GET", query: query, secure: true, @@ -3119,7 +3119,7 @@ export class Api< */ getServiceAccount: (accessKey: string, params: RequestParams = {}) => this.request({ - path: `/service-accounts/${accessKey}`, + path: `/service-accounts/${encodeURIComponent(accessKey)}`, method: "GET", secure: true, format: "json", @@ -3141,7 +3141,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/service-accounts/${accessKey}`, + path: `/service-accounts/${encodeURIComponent(accessKey)}`, method: "PUT", body: body, secure: true, @@ -3160,7 +3160,7 @@ export class Api< */ deleteServiceAccount: (accessKey: string, params: RequestParams = {}) => this.request({ - path: `/service-accounts/${accessKey}`, + path: `/service-accounts/${encodeURIComponent(accessKey)}`, method: "DELETE", secure: true, ...params, @@ -3278,7 +3278,7 @@ export class Api< */ getUserInfo: (name: string, params: RequestParams = {}) => this.request({ - path: `/user/${name}`, + path: `/user/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -3300,7 +3300,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/user/${name}`, + path: `/user/${encodeURIComponent(name)}`, method: "PUT", body: body, secure: true, @@ -3320,7 +3320,7 @@ export class Api< */ removeUser: (name: string, params: RequestParams = {}) => this.request({ - path: `/user/${name}`, + path: `/user/${encodeURIComponent(name)}`, method: "DELETE", secure: true, ...params, @@ -3341,7 +3341,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/user/${name}/groups`, + path: `/user/${encodeURIComponent(name)}/groups`, method: "PUT", body: body, secure: true, @@ -3379,7 +3379,7 @@ export class Api< */ getSaUserPolicy: (name: string, params: RequestParams = {}) => this.request({ - path: `/user/${name}/policies`, + path: `/user/${encodeURIComponent(name)}/policies`, method: "GET", secure: true, format: "json", @@ -3397,7 +3397,7 @@ export class Api< */ listAUserServiceAccounts: (name: string, params: RequestParams = {}) => this.request({ - path: `/user/${name}/service-accounts`, + path: `/user/${encodeURIComponent(name)}/service-accounts`, method: "GET", secure: true, format: "json", @@ -3419,7 +3419,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/user/${name}/service-accounts`, + path: `/user/${encodeURIComponent(name)}/service-accounts`, method: "POST", body: body, secure: true, @@ -3442,7 +3442,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/user/${name}/service-account-credentials`, + path: `/user/${encodeURIComponent(name)}/service-account-credentials`, method: "POST", body: body, secure: true, @@ -3535,7 +3535,7 @@ export class Api< */ groupInfo: (name: string, params: RequestParams = {}) => this.request({ - path: `/group/${name}`, + path: `/group/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -3553,7 +3553,7 @@ export class Api< */ removeGroup: (name: string, params: RequestParams = {}) => this.request({ - path: `/group/${name}`, + path: `/group/${encodeURIComponent(name)}`, method: "DELETE", secure: true, ...params, @@ -3574,7 +3574,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/group/${name}`, + path: `/group/${encodeURIComponent(name)}`, method: "PUT", body: body, secure: true, @@ -3648,7 +3648,7 @@ export class Api< */ listUsersForPolicy: (policy: string, params: RequestParams = {}) => this.request({ - path: `/policies/${policy}/users`, + path: `/policies/${encodeURIComponent(policy)}/users`, method: "GET", secure: true, format: "json", @@ -3666,7 +3666,7 @@ export class Api< */ listGroupsForPolicy: (policy: string, params: RequestParams = {}) => this.request({ - path: `/policies/${policy}/groups`, + path: `/policies/${encodeURIComponent(policy)}/groups`, method: "GET", secure: true, format: "json", @@ -3700,7 +3700,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/bucket-policy/${bucket}`, + path: `/bucket-policy/${encodeURIComponent(bucket)}`, method: "GET", query: query, secure: true, @@ -3724,7 +3724,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/bucket/${bucket}/access-rules`, + path: `/bucket/${encodeURIComponent(bucket)}/access-rules`, method: "PUT", body: prefixaccess, secure: true, @@ -3759,7 +3759,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/bucket/${bucket}/access-rules`, + path: `/bucket/${encodeURIComponent(bucket)}/access-rules`, method: "GET", query: query, secure: true, @@ -3782,7 +3782,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/bucket/${bucket}/access-rules`, + path: `/bucket/${encodeURIComponent(bucket)}/access-rules`, method: "DELETE", body: prefix, secure: true, @@ -3818,7 +3818,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/bucket-users/${bucket}`, + path: `/bucket-users/${encodeURIComponent(bucket)}`, method: "GET", query: query, secure: true, @@ -3838,7 +3838,7 @@ export class Api< */ policyInfo: (name: string, params: RequestParams = {}) => this.request({ - path: `/policy/${name}`, + path: `/policy/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -3856,7 +3856,7 @@ export class Api< */ removePolicy: (name: string, params: RequestParams = {}) => this.request({ - path: `/policy/${name}`, + path: `/policy/${encodeURIComponent(name)}`, method: "DELETE", secure: true, ...params, @@ -3907,7 +3907,7 @@ export class Api< */ configInfo: (name: string, params: RequestParams = {}) => this.request({ - path: `/configs/${name}`, + path: `/configs/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -3929,7 +3929,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/configs/${name}`, + path: `/configs/${encodeURIComponent(name)}`, method: "PUT", body: body, secure: true, @@ -3949,7 +3949,7 @@ export class Api< */ resetConfig: (name: string, params: RequestParams = {}) => this.request({ - path: `/configs/${name}/reset`, + path: `/configs/${encodeURIComponent(name)}/reset`, method: "POST", secure: true, format: "json", @@ -4264,7 +4264,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/admin/info/widgets/${widgetId}`, + path: `/admin/info/widgets/${encodeURIComponent(widgetId)}`, method: "GET", query: query, secure: true, @@ -4511,7 +4511,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/admin/tiers/${type}/${name}`, + path: `/admin/tiers/${encodeURIComponent(type)}/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -4534,7 +4534,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/admin/tiers/${type}/${name}/credentials`, + path: `/admin/tiers/${encodeURIComponent(type)}/${encodeURIComponent(name)}/credentials`, method: "PUT", body: body, secure: true, @@ -4635,7 +4635,7 @@ export class Api< */ remoteBucketDetails: (name: string, params: RequestParams = {}) => this.request({ - path: `/remote-buckets/${name}`, + path: `/remote-buckets/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -4657,7 +4657,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/remote-buckets/${sourceBucketName}/${arn}`, + path: `/remote-buckets/${encodeURIComponent(sourceBucketName)}/${encodeURIComponent(arn)}`, method: "DELETE", secure: true, ...params, @@ -4831,7 +4831,7 @@ export class Api< */ kmsKeyStatus: (name: string, params: RequestParams = {}) => this.request({ - path: `/kms/keys/${name}`, + path: `/kms/keys/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -4849,7 +4849,7 @@ export class Api< */ kmsDeleteKey: (name: string, params: RequestParams = {}) => this.request({ - path: `/kms/keys/${name}`, + path: `/kms/keys/${encodeURIComponent(name)}`, method: "DELETE", secure: true, ...params, @@ -4870,7 +4870,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/kms/keys/${name}/import`, + path: `/kms/keys/${encodeURIComponent(name)}/import`, method: "POST", body: body, secure: true, @@ -4933,7 +4933,7 @@ export class Api< */ kmsGetPolicy: (name: string, params: RequestParams = {}) => this.request({ - path: `/kms/policies/${name}`, + path: `/kms/policies/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -4951,7 +4951,7 @@ export class Api< */ kmsDeletePolicy: (name: string, params: RequestParams = {}) => this.request({ - path: `/kms/policies/${name}`, + path: `/kms/policies/${encodeURIComponent(name)}`, method: "DELETE", secure: true, ...params, @@ -4972,7 +4972,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/kms/policies/${name}/assign`, + path: `/kms/policies/${encodeURIComponent(name)}/assign`, method: "POST", body: body, secure: true, @@ -4991,7 +4991,7 @@ export class Api< */ kmsDescribePolicy: (name: string, params: RequestParams = {}) => this.request({ - path: `/kms/policies/${name}/describe`, + path: `/kms/policies/${encodeURIComponent(name)}/describe`, method: "GET", secure: true, format: "json", @@ -5009,7 +5009,7 @@ export class Api< */ kmsDeleteIdentity: (name: string, params: RequestParams = {}) => this.request({ - path: `/kms/identities/${name}`, + path: `/kms/identities/${encodeURIComponent(name)}`, method: "DELETE", secure: true, ...params, @@ -5026,7 +5026,7 @@ export class Api< */ kmsDescribeIdentity: (name: string, params: RequestParams = {}) => this.request({ - path: `/kms/identities/${name}/describe`, + path: `/kms/identities/${encodeURIComponent(name)}/describe`, method: "GET", secure: true, format: "json", @@ -5092,7 +5092,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/idp/${type}`, + path: `/idp/${encodeURIComponent(type)}`, method: "POST", body: body, secure: true, @@ -5112,7 +5112,7 @@ export class Api< */ listConfigurations: (type: string, params: RequestParams = {}) => this.request({ - path: `/idp/${type}`, + path: `/idp/${encodeURIComponent(type)}`, method: "GET", secure: true, format: "json", @@ -5134,7 +5134,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/idp/${type}/${name}`, + path: `/idp/${encodeURIComponent(type)}/${encodeURIComponent(name)}`, method: "GET", secure: true, format: "json", @@ -5156,7 +5156,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/idp/${type}/${name}`, + path: `/idp/${encodeURIComponent(type)}/${encodeURIComponent(name)}`, method: "DELETE", secure: true, format: "json", @@ -5179,7 +5179,7 @@ export class Api< params: RequestParams = {}, ) => this.request({ - path: `/idp/${type}/${name}`, + path: `/idp/${encodeURIComponent(type)}/${encodeURIComponent(name)}`, method: "PUT", body: body, secure: true, @@ -5290,7 +5290,7 @@ export class Api< */ downloadSharedObject: (url: string, params: RequestParams = {}) => this.request({ - path: `/download-shared-object/${url}`, + path: `/download-shared-object/${encodeURIComponent(url)}`, method: "GET", ...params, }), diff --git a/web-app/src/common/utils.ts b/web-app/src/common/utils.ts index d64955653..0c4df0a8b 100644 --- a/web-app/src/common/utils.ts +++ b/web-app/src/common/utils.ts @@ -467,38 +467,6 @@ export const representationNumber = (number: number | undefined) => { /** Ref https://developer.mozilla.org/en-US/docs/Glossary/Base64 */ -const base64ToBytes = (base64: any): Uint8Array => { - const binString: any = atob(base64); - // @ts-ignore - return Uint8Array.from(binString, (m) => m.codePointAt(0)); -}; - -const bytesToBase64 = (bytes: any) => { - const binString = Array.from(bytes, (x: any) => String.fromCodePoint(x)).join( - "", - ); - return btoa(binString); -}; - -export const encodeURLString = (name: string | null) => { - if (!name) { - return ""; - } - try { - return bytesToBase64(new TextEncoder().encode(name)); - } catch (err) { - return ""; - } -}; - -export const decodeURLString = (text: string) => { - try { - return new TextDecoder().decode(base64ToBytes(text)); - } catch (err) { - return text; - } -}; - export const performDownload = (blob: Blob, fileName: string) => { const link = document.createElement("a"); link.href = window.URL.createObjectURL(blob); diff --git a/web-app/src/screens/Console/Account/DeleteServiceAccount.tsx b/web-app/src/screens/Console/Account/DeleteServiceAccount.tsx index 65253d567..302ad82a1 100644 --- a/web-app/src/screens/Console/Account/DeleteServiceAccount.tsx +++ b/web-app/src/screens/Console/Account/DeleteServiceAccount.tsx @@ -17,7 +17,6 @@ import React, { Fragment, useState } from "react"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; import { ConfirmDeleteIcon } from "mds"; -import { encodeURLString } from "../../../common/utils"; import { setErrorSnackMessage } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import { api } from "api"; @@ -47,7 +46,7 @@ const DeleteServiceAccount = ({ const onConfirmDelete = () => { setLoadingDelete(true); api.serviceAccounts - .deleteServiceAccount(encodeURLString(selectedServiceAccount)) + .deleteServiceAccount(selectedServiceAccount) .then((_) => { closeDeleteModalAndRefresh(true); }) diff --git a/web-app/src/screens/Console/Account/EditServiceAccount.tsx b/web-app/src/screens/Console/Account/EditServiceAccount.tsx index 65c06681a..212b80d9c 100644 --- a/web-app/src/screens/Console/Account/EditServiceAccount.tsx +++ b/web-app/src/screens/Console/Account/EditServiceAccount.tsx @@ -29,7 +29,6 @@ import { errorToHandler } from "api/errors"; import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper"; import { ApiError } from "api/consoleApi"; import { useAppDispatch } from "store"; -import { encodeURLString } from "common/utils"; import { setErrorSnackMessage, setModalErrorSnackMessage } from "systemSlice"; import ModalWrapper from "../Common/ModalWrapper/ModalWrapper"; import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary"; @@ -57,10 +56,9 @@ const EditServiceAccount = ({ useEffect(() => { if (!loading && selectedAccessKey !== "") { - const sourceAccKey = encodeURLString(selectedAccessKey); setLoading(true); api.serviceAccounts - .getServiceAccount(sourceAccKey) + .getServiceAccount(selectedAccessKey || "") .then((res) => { setLoading(false); const saInfo = res.data; @@ -87,7 +85,7 @@ const EditServiceAccount = ({ const setPolicy = (event: React.FormEvent, newPolicy: string) => { event.preventDefault(); api.serviceAccounts - .updateServiceAccount(encodeURLString(selectedAccessKey), { + .updateServiceAccount(selectedAccessKey || "", { policy: newPolicy, description: description, expiry: expiry, diff --git a/web-app/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx b/web-app/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx index 8ad156008..b9cdca015 100644 --- a/web-app/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx +++ b/web-app/src/screens/Console/Buckets/BucketDetails/AccessDetailsPanel.tsx @@ -29,7 +29,6 @@ import { hasPermission, SecureComponent, } from "../../../../common/SecureComponent"; -import { encodeURLString } from "../../../../common/utils"; import { setErrorSnackMessage, setHelpName } from "../../../../systemSlice"; import { selBucketDetailsLoading } from "./bucketDetailsSlice"; import { useAppDispatch } from "../../../../store"; @@ -85,7 +84,7 @@ const AccessDetails = () => { type: "view", disableButtonFunction: () => !viewPolicy, onClick: (policy: any) => { - navigate(`${IAM_PAGES.POLICIES}/${encodeURLString(policy.name)}`); + navigate(`${IAM_PAGES.POLICIES}/${encodeURIComponent(policy.name)}`); }, }, ]; @@ -95,7 +94,7 @@ const AccessDetails = () => { type: "view", disableButtonFunction: () => !viewUser, onClick: (user: any) => { - navigate(`${IAM_PAGES.USERS}/${encodeURLString(user)}`); + navigate(`${IAM_PAGES.USERS}/${encodeURIComponent(user)}`); }, }, ]; diff --git a/web-app/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx b/web-app/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx index 34e141aeb..7791a099a 100644 --- a/web-app/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx +++ b/web-app/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx @@ -20,7 +20,6 @@ import { useLocation, useParams } from "react-router-dom"; import { api } from "api"; import { AppState, useAppDispatch } from "../../../../store"; import { IAM_SCOPES } from "../../../../common/SecureComponent/permissions"; -import { decodeURLString, encodeURLString } from "../../../../common/utils"; import { resetMessages, setIsVersioned, @@ -77,8 +76,11 @@ const BrowserHandler = () => { const records = useSelector((state: AppState) => state.objectBrowser.records); const bucketName = params.bucketName || ""; - const pathSegment = location.pathname.split(`/browser/${bucketName}/`); - const internalPaths = pathSegment.length === 2 ? pathSegment[1] : ""; + const pathSegment = location.pathname.split( + `/browser/${encodeURIComponent(bucketName)}/`, + ); + const internalPaths = + pathSegment.length === 2 ? decodeURIComponent(pathSegment[1]) : ""; const initWSRequest = useCallback( (path: string) => { @@ -105,18 +107,13 @@ const BrowserHandler = () => { // Common path load const pathLoad = useCallback( (forceLoad: boolean = false) => { - const decodedInternalPaths = decodeURLString(internalPaths); - // We exit Versions mode in case of path change dispatch(setVersionsModeEnabled({ status: false })); - let searchPath = decodedInternalPaths; + let searchPath = internalPaths; - if (!decodedInternalPaths.endsWith("/") && decodedInternalPaths !== "") { - searchPath = `${decodedInternalPaths - .split("/") - .slice(0, -1) - .join("/")}/`; + if (!internalPaths.endsWith("/") && internalPaths !== "") { + searchPath = `${internalPaths.split("/").slice(0, -1).join("/")}/`; } if (searchPath === "/") { @@ -151,11 +148,9 @@ const BrowserHandler = () => { // Object Details handler useEffect(() => { - const decodedIPaths = decodeURLString(internalPaths); - dispatch(setLoadingVersioning(true)); - if (decodedIPaths.endsWith("/") || decodedIPaths === "") { + if (internalPaths.endsWith("/") || internalPaths === "") { dispatch(setObjectDetailsView(false)); dispatch(setSelectedObjectView(null)); dispatch(setLoadingLocking(true)); @@ -163,11 +158,7 @@ const BrowserHandler = () => { dispatch(setLoadingObjectInfo(true)); dispatch(setObjectDetailsView(true)); dispatch(setLoadingVersions(true)); - dispatch( - setSelectedObjectView( - `${decodedIPaths ? `${encodeURLString(decodedIPaths)}` : ``}`, - ), - ); + dispatch(setSelectedObjectView(internalPaths || "")); } }, [bucketName, internalPaths, rewindDate, rewindEnabled, dispatch]); diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx index 96d234893..87224c6c7 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreatePathModal.tsx @@ -27,7 +27,6 @@ import { } from "mds"; import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper"; import { modalStyleUtils } from "../../../../Common/FormComponents/common/styleLibrary"; -import { encodeURLString } from "../../../../../../common/utils"; import { BucketObjectItem } from "./types"; import { AppState, useAppDispatch } from "../../../../../../store"; import { setModalErrorSnackMessage } from "../../../../../../systemSlice"; @@ -101,7 +100,7 @@ const CreatePathModal = ({ folderPath = folderPath.slice(1); //trim '/' } - const newPath = `/browser/${bucketName}/${encodeURLString( + const newPath = `/browser/${encodeURIComponent(bucketName)}/${encodeURIComponent( `${folderPath}${cleanPathURL}/`, )}`; diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx index fd57c1bf2..333996104 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteMultipleObjects.tsx @@ -26,7 +26,6 @@ import { IAM_SCOPES } from "../../../../../../common/SecureComponent/permissions import { useSelector } from "react-redux"; import { BucketVersioningResponse } from "api/consoleApi"; import { api } from "../../../../../../api"; -import { encodeURLString } from "../../../../../../common/utils"; interface IDeleteObjectProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -92,7 +91,7 @@ const DeleteObject = ({ const firstObject = selectedObjects[0]; api.buckets .deleteObject(selectedBucket, { - prefix: encodeURLString(firstObject), + prefix: firstObject, all_versions: deleteVersions, bypass: bypassGovernance, recursive: firstObject.endsWith("/"), //if it is just a prefix diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx index a56b60be9..99b3eb135 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteNonCurrent.tsx @@ -16,7 +16,6 @@ import React, { Fragment, useEffect, useState } from "react"; -import { decodeURLString } from "../../../../../../common/utils"; import { ConfirmDeleteIcon, Switch, Grid, InputBox } from "mds"; import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog"; import { setErrorSnackMessage } from "../../../../../../systemSlice"; @@ -102,7 +101,7 @@ const DeleteNonCurrentVersions = ({ confirmationContent={ Are you sure you want to delete all the non-current versions for:{" "} - {decodeURLString(selectedObject)}?
+ {selectedObject}?
{canBypass && (
{ - const decodedSelectedObject = decodeURLString(selectedObject); - const recursive = decodedSelectedObject.endsWith("/"); + const recursive = selectedObject.endsWith("/"); invokeDeleteApi( "DELETE", - `/api/v1/buckets/${selectedBucket}/objects?prefix=${selectedObject}${ + `/api/v1/buckets/${encodeURIComponent(selectedBucket)}/objects?prefix=${encodeURIComponent(selectedObject)}${ selectedVersion !== "" - ? `&version_id=${selectedVersion}` + ? `&version_id=${encodeURIComponent(selectedVersion)}` : `&recursive=${recursive}&all_versions=${deleteVersions}` }${bypassGovernance ? "&bypass=true" : ""}`, ); @@ -100,7 +98,7 @@ const DeleteObject = ({ confirmationContent={ Are you sure you want to delete:
- {decodeURLString(selectedObject)}{" "} + {selectedObject}{" "} {selectedVersion !== "" ? (
diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx index fd3facc42..b81192cc1 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/InspectObject.tsx @@ -24,9 +24,7 @@ import { Box, } from "mds"; import { - decodeURLString, deleteCookie, - encodeURLString, getCookieValue, performDownload, } from "../../../../../../common/utils"; @@ -63,11 +61,8 @@ const InspectObject = ({ }; const performInspect = async () => { - const file = encodeURLString(inspectPath + "/xl.meta"); - const volume = encodeURLString(volumeName); - let basename = document.baseURI.replace(window.location.origin, ""); - const urlOfInspectApi = `${window.location.origin}${basename}/api/v1/admin/inspect?volume=${volume}&file=${file}&encrypt=${isEncrypt}`; + const urlOfInspectApi = `${window.location.origin}${basename}/api/v1/admin/inspect?volume=${encodeURIComponent(volumeName)}&file=${encodeURIComponent(inspectPath + "/xl.meta")}&encrypt=${isEncrypt}`; makeRequest(urlOfInspectApi) .then(async (res) => { @@ -126,8 +121,7 @@ const InspectObject = ({ onSubmit(e); }} > - Would you like to encrypt {decodeURLString(inspectPath)}?{" "} -
+ Would you like to encrypt {inspectPath}?
{ const bucketName = params.bucketName || ""; const pathSegment = location.pathname.split(`/browser/${bucketName}/`); - const internalPaths = pathSegment.length === 2 ? pathSegment[1] : ""; + const internalPaths = + pathSegment.length === 2 ? decodeURIComponent(pathSegment[1]) : ""; - const pageTitle = decodeURLString(internalPaths); - const currentPath = pageTitle.split("/").filter((i: string) => i !== ""); + const currentPath = internalPaths.split("/").filter((i: string) => i !== ""); let uploadPath = [bucketName]; if (currentPath.length > 0) { @@ -316,12 +312,11 @@ const ListObjects = () => { const fetchMetadata = useCallback(() => { const objectName = selectedObjects[0]; - const encodedPath = encodeURLString(objectName); - if (!isMetaDataLoaded && encodedPath) { + if (!isMetaDataLoaded && objectName) { api.buckets .getObjectMetadata(bucketName, { - prefix: encodedPath, + prefix: objectName, }) .then((res) => { let metadata = get(res.data, "objectMetadata", {}); @@ -511,8 +506,6 @@ const ListObjects = () => { const blobFile = new Blob([file], { type: file.type }); - let encodedPath = ""; - const filePath = get(file, "path", ""); const fileWebkitRelativePath = get(file, "webkitRelativePath", ""); @@ -552,17 +545,15 @@ const ListObjects = () => { } if (prefixPath !== "") { - uploadUrl = `${uploadUrl}?prefix=${encodeURLString( + uploadUrl = `${uploadUrl}?prefix=${encodeURIComponent( prefixPath + fileName, )}`; } else { - uploadUrl = `${uploadUrl}?prefix=${encodeURLString(fileName)}`; + uploadUrl = `${uploadUrl}?prefix=${encodeURIComponent(fileName)}`; } - encodedPath = encodeURLString(prefixPath); - - const identity = encodeURLString( - `${bucketName}-${encodedPath}-${new Date().getTime()}-${Math.random()}`, + const identity = encodeURIComponent( + `${bucketName}-${prefixPath}-${new Date().getTime()}-${Math.random()}`, ); let xhr = new XMLHttpRequest(); @@ -666,7 +657,7 @@ const ListObjects = () => { done: false, instanceID: identity, percentage: 0, - prefix: `${decodeURLString(encodedPath)}${fileName}`, + prefix: `${prefixPath}${fileName}`, type: "upload", waitingForFile: false, failed: false, @@ -812,8 +803,7 @@ const ListObjects = () => { if (detailsOpen && selectedInternalPaths !== null) { // We change URL to be the contained folder - const decodedPath = decodeURLString(internalPaths); - const splitURLS = decodedPath.split("/"); + const splitURLS = internalPaths.split("/"); // We remove the last section of the URL as it should be a file splitURLS.pop(); @@ -824,7 +814,9 @@ const ListObjects = () => { URLItem = `${splitURLS.join("/")}/`; } - navigate(`/browser/${bucketName}/${encodeURLString(URLItem)}`); + navigate( + `/browser/${encodeURIComponent(bucketName)}/${encodeURIComponent(URLItem)}`, + ); } dispatch(setObjectDetailsView(false)); @@ -1222,7 +1214,7 @@ const ListObjects = () => { > { const openPath = (object: BucketObject) => { const idElement = object.name || ""; - const newPath = `/browser/${bucketName}${ - idElement ? `/${encodeURLString(idElement)}` : `` + const newPath = `/browser/${encodeURIComponent(bucketName)}${ + idElement ? `/${encodeURIComponent(idElement)}` : `` }`; // for anonymous start download if (anonymousMode && !object.name?.endsWith("/")) { - downloadObject( - dispatch, - bucketName, - `${encodeURLString(idElement)}`, - object, - ); + downloadObject(dispatch, bucketName, idElement, object); return; } dispatch(setSelectedObjects([])); @@ -133,11 +127,7 @@ const ListObjectsTable = () => { dispatch(setObjectDetailsView(true)); dispatch(setLoadingVersions(true)); } - dispatch( - setSelectedObjectView( - `${idElement ? `${encodeURLString(idElement)}` : ``}`, - ), - ); + dispatch(setSelectedObjectView(idElement)); }; const tableActions: ItemActions[] = [ { diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx index 2079058fa..52a222be0 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx @@ -41,7 +41,6 @@ import { downloadObject } from "../../../../ObjectBrowser/utils"; import { BucketObject, BucketVersioningResponse } from "api/consoleApi"; import { AllowedPreviews, previewObjectType } from "../utils"; import { - decodeURLString, niceBytes, niceBytesInt, niceDaysInt, @@ -130,7 +129,7 @@ const ObjectDetailPanel = ({ const [metaData, setMetaData] = useState(null); const [loadMetadata, setLoadingMetadata] = useState(false); - const internalPathsDecoded = decodeURLString(internalPaths) || ""; + const internalPathsDecoded = internalPaths || ""; const allPathData = internalPathsDecoded.split("/"); const currentItem = allPathData.pop() || ""; diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx index aeb91be6f..b2058ee33 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/RestoreFileVersion.tsx @@ -19,7 +19,6 @@ import { Box, RecoverIcon } from "mds"; import { BucketObject } from "api/consoleApi"; import { api } from "api"; import { errorToHandler } from "api/errors"; -import { encodeURLString } from "../../../../../../common/utils"; import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog"; import { setErrorSnackMessage } from "../../../../../../systemSlice"; import { useAppDispatch } from "../../../../../../store"; @@ -48,7 +47,7 @@ const RestoreFileVersion = ({ api.buckets .putObjectRestore(bucketName, { - prefix: encodeURLString(objectPath), + prefix: objectPath, version_id: versionToRestore.version_id || "", }) .then(() => { diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx index 9f0513176..e3874bb43 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetLegalHoldModal.tsx @@ -21,7 +21,6 @@ import { BucketObject, ObjectLegalHoldStatus } from "api/consoleApi"; import { api } from "api"; import { errorToHandler } from "api/errors"; import { modalStyleUtils } from "../../../../Common/FormComponents/common/styleLibrary"; -import { encodeURLString } from "../../../../../../common/utils"; import { setModalErrorSnackMessage } from "../../../../../../systemSlice"; import { useAppDispatch } from "../../../../../../store"; import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper"; @@ -59,7 +58,7 @@ const SetLegalHoldModal = ({ .putObjectLegalHold( bucketName, { - prefix: encodeURLString(objectName), + prefix: objectName, version_id: versionId || "", }, { diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx index 02503fa82..823c7a58a 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/SetRetention.tsx @@ -20,7 +20,6 @@ import { useSelector } from "react-redux"; import { BucketObject, ObjectRetentionMode } from "api/consoleApi"; import { api } from "api"; import { errorToHandler } from "api/errors"; -import { encodeURLString } from "common/utils"; import { modalStyleUtils } from "../../../../Common/FormComponents/common/styleLibrary"; import { twoDigitDate } from "../../../../Common/FormComponents/DateSelector/utils"; import { setModalErrorSnackMessage } from "../../../../../../systemSlice"; @@ -106,7 +105,7 @@ const SetRetention = ({ .putObjectRetention( bucketName, { - prefix: encodeURLString(selectedObject), + prefix: selectedObject, version_id: versionId || "", }, { @@ -130,7 +129,7 @@ const SetRetention = ({ ) => { api.buckets .deleteObjectRetention(bucketName, { - prefix: encodeURLString(selectedObject), + prefix: selectedObject, version_id: versionId || "", }) .then(() => { diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx index 92d77193d..832e389c4 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx @@ -28,10 +28,7 @@ import { import CopyToClipboard from "react-copy-to-clipboard"; import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper"; import DaysSelector from "../../../../Common/FormComponents/DaysSelector/DaysSelector"; -import { - encodeURLString, - niceTimeFromSeconds, -} from "../../../../../../common/utils"; +import { niceTimeFromSeconds } from "../../../../../../common/utils"; import { selDistSet, setModalErrorSnackMessage, @@ -90,7 +87,7 @@ const ShareFile = ({ if (distributedSetup) { api.buckets .listObjects(bucketName, { - prefix: encodeURLString(dataObject.name || ""), + prefix: dataObject.name || "", with_versions: distributedSetup, }) .then((res) => { @@ -138,7 +135,7 @@ const ShareFile = ({ if (diffDate > 0) { api.buckets .shareObject(bucketName, { - prefix: encodeURLString(dataObject.name || ""), + prefix: dataObject.name || "", version_id: versionID, expires: selectedDate !== "" ? `${diffDate}s` : "", }) diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx index dac8a0878..ad38da978 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/TagsModal.tsx @@ -32,7 +32,6 @@ import { import { BucketObject } from "api/consoleApi"; import { api } from "api"; import { errorToHandler } from "api/errors"; -import { encodeURLString } from "common/utils"; import { useSelector } from "react-redux"; import ModalWrapper from "../../../../Common/ModalWrapper/ModalWrapper"; import { modalStyleUtils } from "../../../../Common/FormComponents/common/styleLibrary"; @@ -71,8 +70,6 @@ const AddTagModal = ({ const [deleteKey, setDeleteKey] = useState(""); const [deleteLabel, setDeleteLabel] = useState(""); - const selectedObject = encodeURLString(actualInfo.name || ""); - const currentTags = actualInfo.tags; const currTagKeys = Object.keys(currentTags || {}); @@ -96,7 +93,7 @@ const AddTagModal = ({ api.buckets .putObjectTags( bucketName, - { prefix: selectedObject, version_id: verID }, + { prefix: actualInfo.name || "", version_id: verID }, { tags: newTagList }, ) .then(() => { @@ -118,7 +115,7 @@ const AddTagModal = ({ api.buckets .putObjectTags( bucketName, - { prefix: selectedObject, version_id: verID }, + { prefix: actualInfo.name || "", version_id: verID }, { tags: cleanObject }, ) .then(() => { diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx index 2f8a61c7d..b832967af 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx @@ -31,7 +31,7 @@ import { } from "mds"; import ShareFile from "./ShareFile"; -import { decodeURLString, niceBytesInt } from "../../../../../../common/utils"; +import { niceBytesInt } from "../../../../../../common/utils"; import RestoreFileVersion from "./RestoreFileVersion"; import { AppState, useAppDispatch } from "../../../../../../store"; @@ -128,11 +128,9 @@ const VersionsNavigator = ({ .then((res) => { const result = get(res.data, "objects", []); - const decodedInternalPaths = decodeURLString(internalPaths); - // Filter the results prefixes as API can return more files than expected. const filteredPrefixes = result.filter( - (item: BucketObject) => item.name === decodedInternalPaths, + (item: BucketObject) => item.name === internalPaths, ); if (distributedSetup) { @@ -356,7 +354,7 @@ const VersionsNavigator = ({ {delSelectedVOpen && ( diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx index 72c1546a6..44a005130 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/Preview/PreviewFileContent.tsx @@ -18,7 +18,6 @@ import React, { Fragment, useCallback, useEffect, useState } from "react"; import { ProgressBar, Grid, Box, InformativeMessage } from "mds"; import get from "lodash/get"; import { AllowedPreviews, previewObjectType } from "../utils"; -import { encodeURLString } from "../../../../../../common/utils"; import { api } from "../../../../../../api"; import PreviewPDF from "./PreviewPDF"; import { downloadObject } from "../../../../ObjectBrowser/utils"; @@ -47,10 +46,9 @@ const PreviewFile = ({ const fetchMetadata = useCallback(() => { if (!isMetaDataLoaded) { - const encodedPath = encodeURLString(objectName); api.buckets .getObjectMetadata(bucketName, { - prefix: encodedPath, + prefix: objectName, versionID: actualInfo.version_id || "", }) .then((res) => { @@ -78,9 +76,8 @@ const PreviewFile = ({ let path = ""; if (actualInfo) { - const encodedPath = encodeURLString(actualInfo.name || ""); let basename = document.baseURI.replace(window.location.origin, ""); - path = `${window.location.origin}${basename}api/v1/buckets/${bucketName}/objects/download?preview=true&prefix=${encodedPath}`; + path = `${window.location.origin}${basename}api/v1/buckets/${encodeURIComponent(bucketName)}/objects/download?preview=true&prefix=${encodeURIComponent(actualInfo.name || "")}`; if (actualInfo.version_id) { path = path.concat(`&version_id=${actualInfo.version_id}`); } diff --git a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts index 4873f87bf..7030f07ec 100644 --- a/web-app/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts +++ b/web-app/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts @@ -15,7 +15,6 @@ // along with this program. If not, see . import { BucketObjectItem } from "./ListObjects/types"; -import { decodeURLString, encodeURLString } from "../../../../../common/utils"; import { removeTrace } from "../../../ObjectBrowser/transferManager"; import store from "../../../../../store"; import { ContentType, PermissionResource } from "api/consoleApi"; @@ -66,7 +65,7 @@ export const downloadSelectedAsZip = async ( }; const isFolder = (objectPath: string) => { - return decodeURLString(objectPath).endsWith("/"); + return objectPath.endsWith("/"); }; export const download = ( @@ -88,9 +87,9 @@ export const download = ( let path = `${ window.location.origin - }${basename}api/v1/buckets/${bucketName}/objects/download?prefix=${objectPath}${ + }${basename}api/v1/buckets/${encodeURIComponent(bucketName)}/objects/download?prefix=${encodeURIComponent(objectPath)}${ overrideFileName !== null && overrideFileName.trim() !== "" - ? `&override_file_name=${encodeURLString(overrideFileName || "")}` + ? `&override_file_name=${encodeURIComponent(overrideFileName || "")}` : "" }`; if (versionID) { diff --git a/web-app/src/screens/Console/Groups/AddGroupMember.tsx b/web-app/src/screens/Console/Groups/AddGroupMember.tsx index 1f5b7fd27..640cc8d65 100644 --- a/web-app/src/screens/Console/Groups/AddGroupMember.tsx +++ b/web-app/src/screens/Console/Groups/AddGroupMember.tsx @@ -17,7 +17,6 @@ import React, { useState } from "react"; import { AddMembersToGroupIcon, Button, FormLayout, Grid, ReadBox } from "mds"; import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary"; -import { encodeURLString } from "../../../common/utils"; import { setModalErrorSnackMessage } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import { api } from "api"; @@ -48,7 +47,7 @@ const AddGroupMember = ({ function addMembersToGroup() { return api.group - .updateGroup(encodeURLString(selectedGroup), { + .updateGroup(selectedGroup, { members: selectedUsers, status: groupStatus, }) diff --git a/web-app/src/screens/Console/Groups/DeleteGroup.tsx b/web-app/src/screens/Console/Groups/DeleteGroup.tsx index 1f937a6e3..5f01b9a01 100644 --- a/web-app/src/screens/Console/Groups/DeleteGroup.tsx +++ b/web-app/src/screens/Console/Groups/DeleteGroup.tsx @@ -16,7 +16,6 @@ import React, { Fragment, useState } from "react"; import { ConfirmDeleteIcon } from "mds"; -import { encodeURLString } from "../../../common/utils"; import { setErrorSnackMessage } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; @@ -46,7 +45,7 @@ const DeleteGroup = ({ for (let group of selectedGroups) { setLoadingDelete(true); api.group - .removeGroup(encodeURLString(group)) + .removeGroup(group) .then((_) => { closeDeleteModalAndRefresh(true); }) diff --git a/web-app/src/screens/Console/Groups/Groups.tsx b/web-app/src/screens/Console/Groups/Groups.tsx index 110553f3e..82d8f5054 100644 --- a/web-app/src/screens/Console/Groups/Groups.tsx +++ b/web-app/src/screens/Console/Groups/Groups.tsx @@ -51,7 +51,6 @@ import { } from "../../../common/SecureComponent"; import { errorToHandler } from "../../../api/errors"; import withSuspense from "../Common/Components/withSuspense"; -import { encodeURLString } from "../../../common/utils"; import { setErrorSnackMessage, setHelpName } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import TooltipWrapper from "../Common/TooltipWrapper/TooltipWrapper"; @@ -163,7 +162,7 @@ const Groups = () => { ); const viewAction = (group: any) => { - navigate(`${IAM_PAGES.GROUPS}/${encodeURLString(group)}`); + navigate(`${IAM_PAGES.GROUPS}/${encodeURIComponent(group)}`); }; const tableActions = [ diff --git a/web-app/src/screens/Console/Groups/GroupsDetails.tsx b/web-app/src/screens/Console/Groups/GroupsDetails.tsx index 9334fa104..db77ea190 100644 --- a/web-app/src/screens/Console/Groups/GroupsDetails.tsx +++ b/web-app/src/screens/Console/Groups/GroupsDetails.tsx @@ -53,7 +53,6 @@ import { hasPermission, SecureComponent, } from "../../../common/SecureComponent"; -import { decodeURLString, encodeURLString } from "../../../common/utils"; import { setHelpName, setModalErrorSnackMessage } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import { setSelectedPolicies } from "../Users/AddUsersSlice"; @@ -82,8 +81,6 @@ const GroupsDetails = () => { const [memberFilter, setMemberFilter] = useState(""); const [currentTab, setCurrentTab] = useState("members"); - const groupName = decodeURLString(params.groupName || ""); - const { members = [], policy = "", status: groupEnabled } = groupDetails; const filteredMembers = members.filter((elementItem) => @@ -102,11 +99,11 @@ const GroupsDetails = () => { }, []); useEffect(() => { - if (groupName) { + if (params.groupName) { fetchGroupInfo(); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [groupName]); + }, [params.groupName]); const groupPolicies = formatPolicy(policy); const isGroupEnabled = groupEnabled === "enabled"; @@ -138,7 +135,7 @@ const GroupsDetails = () => { function fetchGroupInfo() { if (getGroupDetails) { api.group - .groupInfo(encodeURLString(groupName)) + .groupInfo(params.groupName || "") .then((res) => { setGroupDetails(res.data); }) @@ -151,7 +148,7 @@ const GroupsDetails = () => { function toggleGroupStatus(nextStatus: boolean) { return api.group - .updateGroup(encodeURLString(groupName), { + .updateGroup(params.groupName || "", { members: members, status: nextStatus ? "enabled" : "disabled", }) @@ -242,7 +239,9 @@ const GroupsDetails = () => { { type: "view", onClick: (userName) => { - navigate(`${IAM_PAGES.USERS}/${encodeURLString(userName)}`); + navigate( + `${IAM_PAGES.USERS}/${encodeURIComponent(userName)}`, + ); }, isDisabled: !viewUser, }, @@ -312,7 +311,9 @@ const GroupsDetails = () => { { type: "view", onClick: (policy) => { - navigate(`${IAM_PAGES.POLICIES}/${encodeURLString(policy)}`); + navigate( + `${IAM_PAGES.POLICIES}/${encodeURIComponent(policy)}`, + ); }, isDisabled: !canViewPolicy, }, @@ -332,7 +333,7 @@ const GroupsDetails = () => { {policyOpen ? ( { setPolicyOpen(false); @@ -344,7 +345,7 @@ const GroupsDetails = () => { {usersOpen ? ( {}} title={memberActionText} groupStatus={groupEnabled} @@ -360,7 +361,7 @@ const GroupsDetails = () => { {deleteOpen && ( { setDeleteOpen(false); if (isDelSuccess) { @@ -388,7 +389,7 @@ const GroupsDetails = () => {
} - title={groupName} + title={params.groupName || ""} subTitle={null} bottomBorder actions={ diff --git a/web-app/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx b/web-app/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx index 57c76b947..b9e27d956 100644 --- a/web-app/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx +++ b/web-app/src/screens/Console/ObjectBrowser/BrowserBreadcrumbs.tsx @@ -19,7 +19,7 @@ import { useSelector } from "react-redux"; import CopyToClipboard from "react-copy-to-clipboard"; import styled from "styled-components"; import { Link, useNavigate } from "react-router-dom"; -import { encodeURLString, safeDecodeURIComponent } from "../../../common/utils"; +import { safeDecodeURIComponent } from "../../../common/utils"; import { Button, CopyIcon, @@ -137,8 +137,8 @@ const BrowserBreadcrumbs = ({ let breadcrumbsMap = splitPaths.map((objectItem: string, index: number) => { const subSplit = `${splitPaths.slice(0, index + 1).join("/")}/`; - const route = `/browser/${bucketName}/${ - subSplit ? `${encodeURLString(subSplit)}` : `` + const route = `/browser/${encodeURIComponent(bucketName)}/${ + subSplit ? `${encodeURIComponent(subSplit)}` : `` }`; if (index === lastBreadcrumbsIndex && objectItem === versionedFile) { @@ -222,7 +222,7 @@ const BrowserBreadcrumbs = ({ navigate( `/browser/${bucketName}${ prevPath.length > 0 - ? `/${encodeURLString(`${prevPath.join("/")}/`)}` + ? `/${encodeURIComponent(`${prevPath.join("/")}/`)}` : "" }`, ); diff --git a/web-app/src/screens/Console/ObjectBrowser/objectBrowserThunks.ts b/web-app/src/screens/Console/ObjectBrowser/objectBrowserThunks.ts index d055d69af..dbe32d4a5 100644 --- a/web-app/src/screens/Console/ObjectBrowser/objectBrowserThunks.ts +++ b/web-app/src/screens/Console/ObjectBrowser/objectBrowserThunks.ts @@ -16,7 +16,7 @@ import { createAsyncThunk } from "@reduxjs/toolkit"; import { AppState } from "../../../store"; -import { encodeURLString, getClientOS } from "../../../common/utils"; +import { getClientOS } from "../../../common/utils"; import { BucketObjectItem } from "../Buckets/ListBuckets/Objects/ListObjects/types"; import { makeid, storeCallForObjectWithID } from "./transferManager"; import { @@ -46,7 +46,7 @@ export const downloadSelected = createAsyncThunk( const state = getState() as AppState; const downloadObject = (object: BucketObjectItem) => { - const identityDownload = encodeURLString( + const identityDownload = encodeURIComponent( `${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}`, ); @@ -54,7 +54,7 @@ export const downloadSelected = createAsyncThunk( const downloadCall = download( bucketName, - encodeURLString(object.name), + object.name, object.version_id, object.size, null, diff --git a/web-app/src/screens/Console/ObjectBrowser/utils.ts b/web-app/src/screens/Console/ObjectBrowser/utils.ts index 03c45c5ea..0fa88a450 100644 --- a/web-app/src/screens/Console/ObjectBrowser/utils.ts +++ b/web-app/src/screens/Console/ObjectBrowser/utils.ts @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { encodeURLString, getClientOS } from "../../../common/utils"; +import { getClientOS } from "../../../common/utils"; import { makeid, storeCallForObjectWithID } from "./transferManager"; import { download } from "../Buckets/ListBuckets/Objects/utils"; import { @@ -35,7 +35,7 @@ export const downloadObject = ( internalPaths: string, object: BucketObject, ) => { - const identityDownload = encodeURLString( + const identityDownload = encodeURIComponent( `${bucketName}-${object.name}-${new Date().getTime()}-${Math.random()}`, ); diff --git a/web-app/src/screens/Console/Policies/DeletePolicy.tsx b/web-app/src/screens/Console/Policies/DeletePolicy.tsx index 695eea8c5..13b28149b 100644 --- a/web-app/src/screens/Console/Policies/DeletePolicy.tsx +++ b/web-app/src/screens/Console/Policies/DeletePolicy.tsx @@ -22,7 +22,6 @@ import { useAppDispatch } from "../../../store"; import { api } from "api"; import { ApiError, HttpResponse } from "api/consoleApi"; import { errorToHandler } from "api/errors"; -import { encodeURLString } from "common/utils"; interface IDeletePolicyProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -47,7 +46,7 @@ const DeletePolicy = ({ const onConfirmDelete = () => { setLoadingDelete(true); api.policy - .removePolicy(encodeURLString(selectedPolicy)) + .removePolicy(selectedPolicy) .then((_) => { closeDeleteModalAndRefresh(true); }) diff --git a/web-app/src/screens/Console/Policies/ListPolicies.tsx b/web-app/src/screens/Console/Policies/ListPolicies.tsx index 35fe92d1c..80b8cb89f 100644 --- a/web-app/src/screens/Console/Policies/ListPolicies.tsx +++ b/web-app/src/screens/Console/Policies/ListPolicies.tsx @@ -42,7 +42,6 @@ import { SecureComponent, } from "../../../common/SecureComponent"; import { Policy } from "../../../api/consoleApi"; -import { encodeURLString } from "../../../common/utils"; import { setErrorSnackMessage, setHelpName } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import { api } from "../../../api"; @@ -142,7 +141,7 @@ const ListPolicies = () => { }; const viewAction = (policy: any) => { - navigate(`${IAM_PAGES.POLICIES}/${encodeURLString(policy.name)}`); + navigate(`${IAM_PAGES.POLICIES}/${encodeURIComponent(policy.name)}`); }; const tableActions = [ diff --git a/web-app/src/screens/Console/Policies/PolicyDetails.tsx b/web-app/src/screens/Console/Policies/PolicyDetails.tsx index 9f6d120e5..66de9c20e 100644 --- a/web-app/src/screens/Console/Policies/PolicyDetails.tsx +++ b/web-app/src/screens/Console/Policies/PolicyDetails.tsx @@ -59,7 +59,6 @@ import { import withSuspense from "../Common/Components/withSuspense"; import PolicyView from "./PolicyView"; -import { decodeURLString, encodeURLString } from "../../../common/utils"; import { setErrorSnackMessage, setHelpName, @@ -89,7 +88,7 @@ const PolicyDetails = () => { const [groupList, setGroupList] = useState([]); const [addLoading, setAddLoading] = useState(false); - const policyName = decodeURLString(params.policyName || ""); + const policyName = params.policyName || ""; const [policyDefinition, setPolicyDefinition] = useState(""); const [loadingPolicy, setLoadingPolicy] = useState(true); @@ -183,7 +182,7 @@ const PolicyDetails = () => { if (loadingUsers) { if (displayUsers && !ldapIsEnabled) { api.policies - .listUsersForPolicy(encodeURLString(policyName)) + .listUsersForPolicy(policyName) .then((result) => { setUserList(result.data ?? []); setLoadingUsers(false); @@ -202,7 +201,7 @@ const PolicyDetails = () => { if (loadingGroups) { if (displayGroups && !ldapIsEnabled) { api.policies - .listGroupsForPolicy(encodeURLString(policyName)) + .listGroupsForPolicy(policyName) .then((result) => { setGroupList(result.data ?? []); setLoadingGroups(false); @@ -220,7 +219,7 @@ const PolicyDetails = () => { if (loadingPolicy) { if (displayPolicy) { api.policy - .policyInfo(encodeURLString(policyName)) + .policyInfo(policyName) .then((result) => { if (result.data) { setPolicy(result.data); @@ -283,7 +282,7 @@ const PolicyDetails = () => { }; const userViewAction = (user: any) => { - navigate(`${IAM_PAGES.USERS}/${encodeURLString(user)}`); + navigate(`${IAM_PAGES.USERS}/${encodeURIComponent(user)}`); }; const userTableActions = [ { @@ -298,7 +297,7 @@ const PolicyDetails = () => { ); const groupViewAction = (group: any) => { - navigate(`${IAM_PAGES.GROUPS}/${encodeURLString(group)}`); + navigate(`${IAM_PAGES.GROUPS}/${encodeURIComponent(group)}`); }; const groupTableActions = [ diff --git a/web-app/src/screens/Console/Policies/SetPolicy.tsx b/web-app/src/screens/Console/Policies/SetPolicy.tsx index 1e483056b..4d973c7ac 100644 --- a/web-app/src/screens/Console/Policies/SetPolicy.tsx +++ b/web-app/src/screens/Console/Policies/SetPolicy.tsx @@ -20,7 +20,6 @@ import { useSelector } from "react-redux"; import { Button, FormLayout, ReadBox, Grid, ProgressBar } from "mds"; import { ErrorResponseHandler } from "../../../common/types"; -import { encodeURLString } from "../../../common/utils"; import { setModalErrorSnackMessage } from "../../../systemSlice"; import { AppState, useAppDispatch } from "../../../store"; import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary"; @@ -83,7 +82,7 @@ const SetPolicy = ({ const fetchGroupInformation = () => { if (selectedGroups?.length === 1) { api - .invoke("GET", `/api/v1/group/${encodeURLString(selectedGroups[0])}`) + .invoke("GET", `/api/v1/group/${encodeURIComponent(selectedGroups[0])}`) .then((res: any) => { const groupPolicy: String = get(res, "policy", ""); setActualPolicy(groupPolicy.split(",")); diff --git a/web-app/src/screens/Console/Tools/Inspect.tsx b/web-app/src/screens/Console/Tools/Inspect.tsx index 2bd2b4f1b..5e6d1eba7 100644 --- a/web-app/src/screens/Console/Tools/Inspect.tsx +++ b/web-app/src/screens/Console/Tools/Inspect.tsx @@ -31,7 +31,6 @@ import { useNavigate } from "react-router-dom"; import { useSelector } from "react-redux"; import { deleteCookie, - encodeURLString, getCookieValue, performDownload, } from "../../../common/utils"; @@ -143,11 +142,8 @@ const Inspect = () => { }; const performInspect = async () => { - const file = encodeURLString(inspectPath); - const volume = encodeURLString(volumeName); - let basename = document.baseURI.replace(window.location.origin, ""); - const urlOfInspectApi = `${basename}/api/v1/admin/inspect?volume=${volume}&file=${file}&encrypt=${isEncrypt}`; + const urlOfInspectApi = `${basename}/api/v1/admin/inspect?volume=${encodeURIComponent(volumeName)}&file=${encodeURIComponent(inspectPath)}&encrypt=${isEncrypt}`; makeRequest(urlOfInspectApi) .then(async (res) => { diff --git a/web-app/src/screens/Console/Users/AddUserServiceAccountScreen.tsx b/web-app/src/screens/Console/Users/AddUserServiceAccountScreen.tsx index dda9f0bbf..84ba58696 100644 --- a/web-app/src/screens/Console/Users/AddUserServiceAccountScreen.tsx +++ b/web-app/src/screens/Console/Users/AddUserServiceAccountScreen.tsx @@ -35,11 +35,7 @@ import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary"; import { NewServiceAccount } from "../Common/CredentialsPrompt/types"; import { IAM_PAGES } from "../../../common/SecureComponent/permissions"; import { ErrorResponseHandler } from "../../../common/types"; -import { - decodeURLString, - encodeURLString, - getRandomString, -} from "../../../common/utils"; +import { getRandomString } from "../../../common/utils"; import { setErrorSnackMessage, setHelpName } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import CodeMirrorWrapper from "../Common/FormComponents/CodeMirrorWrapper/CodeMirrorWrapper"; @@ -64,7 +60,7 @@ const AddServiceAccount = () => { useState(null); const [policyJSON, setPolicyJSON] = useState(""); - const userName = decodeURLString(params.userName || ""); + const userName = params.userName || ""; const [name, setName] = useState(""); const [description, setDescription] = useState(""); @@ -77,7 +73,7 @@ const AddServiceAccount = () => { api .invoke( "POST", - `/api/v1/user/${encodeURLString( + `/api/v1/user/${encodeURIComponent( userName, )}/service-account-credentials`, { @@ -120,7 +116,7 @@ const AddServiceAccount = () => { useEffect(() => { if (isRestrictedByPolicy) { api - .invoke("GET", `/api/v1/user/${encodeURLString(userName)}/policies`) + .invoke("GET", `/api/v1/user/${encodeURIComponent(userName)}/policies`) .then((res) => { setPolicyJSON(JSON.stringify(JSON.parse(res.policy), null, 4)); @@ -144,7 +140,7 @@ const AddServiceAccount = () => { const closeCredentialsModal = () => { setNewServiceAccount(null); - navigate(`${IAM_PAGES.USERS}/${encodeURLString(userName)}`); + navigate(`${IAM_PAGES.USERS}/${encodeURIComponent(userName)}`); }; useEffect(() => { @@ -169,7 +165,7 @@ const AddServiceAccount = () => { label={ - navigate(`${IAM_PAGES.USERS}/${encodeURLString(userName)}`) + navigate(`${IAM_PAGES.USERS}/${encodeURIComponent(userName)}`) } label={"User Details - " + userName} /> diff --git a/web-app/src/screens/Console/Users/ChangeUserGroups.tsx b/web-app/src/screens/Console/Users/ChangeUserGroups.tsx index d6d02572c..dea6b908b 100644 --- a/web-app/src/screens/Console/Users/ChangeUserGroups.tsx +++ b/web-app/src/screens/Console/Users/ChangeUserGroups.tsx @@ -26,7 +26,6 @@ import { } from "mds"; import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary"; import { ErrorResponseHandler } from "../../../common/types"; -import { encodeURLString } from "../../../common/utils"; import { setModalErrorSnackMessage } from "../../../systemSlice"; import { useAppDispatch } from "../../../store"; import api from "../../../common/api"; @@ -57,7 +56,7 @@ const ChangeUserGroups = ({ } api - .invoke("GET", `/api/v1/user/${encodeURLString(selectedUser)}`) + .invoke("GET", `/api/v1/user/${encodeURIComponent(selectedUser)}`) .then((res) => { setAddLoading(false); setAccessKey(res.accessKey); @@ -89,7 +88,7 @@ const ChangeUserGroups = ({ setAddLoading(true); if (selectedUser !== null) { api - .invoke("PUT", `/api/v1/user/${encodeURLString(selectedUser)}`, { + .invoke("PUT", `/api/v1/user/${encodeURIComponent(selectedUser)}`, { status: enabled ? "enabled" : "disabled", groups: selectedGroups, }) diff --git a/web-app/src/screens/Console/Users/DeleteUser.tsx b/web-app/src/screens/Console/Users/DeleteUser.tsx index 4ffc92628..28112af76 100644 --- a/web-app/src/screens/Console/Users/DeleteUser.tsx +++ b/web-app/src/screens/Console/Users/DeleteUser.tsx @@ -18,7 +18,6 @@ import React, { Fragment, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { setErrorSnackMessage } from "../../../systemSlice"; import { ConfirmDeleteIcon, DataTable, InformativeMessage, Loader } from "mds"; -import { encodeURLString } from "../../../common/utils"; import { IAM_PAGES } from "../../../common/SecureComponent/permissions"; import ConfirmDialog from "../Common/ModalWrapper/ConfirmDialog"; import { useAppDispatch } from "../../../store"; @@ -78,7 +77,7 @@ const DeleteUser = ({ )); const viewAction = (selectionElement: any): void => { navigate( - `${IAM_PAGES.USERS}/${encodeURLString(selectionElement.userName)}`, + `${IAM_PAGES.USERS}/${encodeURIComponent(selectionElement.userName)}`, ); onClose(); }; @@ -101,7 +100,7 @@ const DeleteUser = ({ closeDeleteModalAndRefresh(true); } else { api.user - .removeUser(encodeURLString(user)) + .removeUser(user) .then((res) => { closeDeleteModalAndRefresh(true); navigate(`${IAM_PAGES.USERS}`); diff --git a/web-app/src/screens/Console/Users/ListUsers.tsx b/web-app/src/screens/Console/Users/ListUsers.tsx index 78de6ec17..ad083e51e 100644 --- a/web-app/src/screens/Console/Users/ListUsers.tsx +++ b/web-app/src/screens/Console/Users/ListUsers.tsx @@ -34,7 +34,6 @@ import { User, UsersList } from "./types"; import { usersSort } from "../../../utils/sortFunctions"; import { actionsTray } from "../Common/FormComponents/common/styleLibrary"; import { ErrorResponseHandler } from "../../../common/types"; -import { encodeURLString } from "../../../common/utils"; import { addUserToGroupPermissions, CONSOLE_UI_RESOURCE, @@ -148,7 +147,7 @@ const ListUsers = () => { const viewAction = (selectionElement: any): void => { navigate( - `${IAM_PAGES.USERS}/${encodeURLString(selectionElement.accessKey)}`, + `${IAM_PAGES.USERS}/${encodeURIComponent(selectionElement.accessKey)}`, ); }; diff --git a/web-app/src/screens/Console/Users/UserDetails.tsx b/web-app/src/screens/Console/Users/UserDetails.tsx index 53460e679..0a26d6bdb 100644 --- a/web-app/src/screens/Console/Users/UserDetails.tsx +++ b/web-app/src/screens/Console/Users/UserDetails.tsx @@ -35,7 +35,6 @@ import { } from "mds"; import { IPolicyItem } from "./types"; import { ErrorResponseHandler } from "../../../common/types"; -import { decodeURLString, encodeURLString } from "../../../common/utils"; import { setHelpName, setModalErrorSnackMessage } from "../../../systemSlice"; import { assignGroupPermissions, @@ -91,7 +90,7 @@ const UserDetails = () => { const disableEnabled = hasPermission(CONSOLE_UI_RESOURCE, disableUserPermissions) && enabled; - const userName = decodeURLString(params.userName || ""); + const userName = params.userName || ""; const changeUserPassword = () => { setChangeUserPasswordModalOpen(true); @@ -121,7 +120,7 @@ const UserDetails = () => { } setLoading(true); api - .invoke("GET", `/api/v1/user/${encodeURLString(userName)}`) + .invoke("GET", `/api/v1/user/${encodeURIComponent(userName)}`) .then((res) => { setAddLoading(false); const memberOf = res.memberOf || []; @@ -162,7 +161,7 @@ const UserDetails = () => { } setAddLoading(true); api - .invoke("PUT", `/api/v1/user/${encodeURLString(userName)}`, { + .invoke("PUT", `/api/v1/user/${encodeURIComponent(userName)}`, { status: isEnabled ? "enabled" : "disabled", groups: selectedGroups, }) @@ -192,7 +191,7 @@ const UserDetails = () => { }; const groupViewAction = (group: any) => { - navigate(`${IAM_PAGES.GROUPS}/${encodeURLString(group.group)}`); + navigate(`${IAM_PAGES.GROUPS}/${encodeURIComponent(group.group)}`); }; const groupTableActions = [ @@ -493,7 +492,7 @@ const UserDetails = () => { type: "view", onClick: (policy: IPolicyItem) => { navigate( - `${IAM_PAGES.POLICIES}/${encodeURLString( + `${IAM_PAGES.POLICIES}/${encodeURIComponent( policy.policy, )}`, ); diff --git a/web-app/src/screens/Console/Users/UserServiceAccountsPanel.tsx b/web-app/src/screens/Console/Users/UserServiceAccountsPanel.tsx index c50f17864..b0b5c53dc 100644 --- a/web-app/src/screens/Console/Users/UserServiceAccountsPanel.tsx +++ b/web-app/src/screens/Console/Users/UserServiceAccountsPanel.tsx @@ -31,7 +31,6 @@ import { IAM_SCOPES, } from "../../../common/SecureComponent/permissions"; import { SecureComponent } from "../../../common/SecureComponent"; -import { encodeURLString } from "../../../common/utils"; import { setErrorSnackMessage, setHelpName, @@ -75,7 +74,10 @@ const UserServiceAccountsPanel = ({ useEffect(() => { if (loading) { api - .invoke("GET", `/api/v1/user/${encodeURLString(user)}/service-accounts`) + .invoke( + "GET", + `/api/v1/user/${encodeURIComponent(user)}/service-accounts`, + ) .then((res: ServiceAccounts) => { setLoading(false); const sortedRows = res.sort(usersSort); @@ -233,7 +235,7 @@ const UserServiceAccountsPanel = ({ icon={} onClick={() => { navigate( - `/identity/users/new-user-sa/${encodeURLString(user)}`, + `/identity/users/new-user-sa/${encodeURIComponent(user)}`, ); }} disabled={!hasPolicy} diff --git a/web-app/src/websockets/objectBrowserWSMiddleware.ts b/web-app/src/websockets/objectBrowserWSMiddleware.ts index 5acdfbea8..d79050856 100644 --- a/web-app/src/websockets/objectBrowserWSMiddleware.ts +++ b/web-app/src/websockets/objectBrowserWSMiddleware.ts @@ -34,7 +34,6 @@ import { WebsocketRequest, WebsocketResponse, } from "../screens/Console/Buckets/ListBuckets/Objects/ListObjects/types"; -import { decodeURLString, encodeURLString } from "../common/utils"; import { permissionItems } from "../screens/Console/Buckets/ListBuckets/Objects/utils"; import { setErrorSnackMessage } from "../systemSlice"; @@ -108,11 +107,9 @@ export const objectBrowserWSMiddleware = ( let pathPrefix = ""; if (internalPathsPrefix) { - const decodedPath = decodeURLString(internalPathsPrefix); - - pathPrefix = decodedPath.endsWith("/") - ? decodedPath - : decodedPath + "/"; + pathPrefix = internalPathsPrefix.endsWith("/") + ? internalPathsPrefix + : internalPathsPrefix + "/"; } const permitItems = permissionItems( @@ -202,7 +199,7 @@ export const objectBrowserWSMiddleware = ( const request: WebsocketRequest = { bucket_name: dataPayload.bucketName, - prefix: encodeURLString(dataPayload.path), + prefix: dataPayload.path, mode: dataPayload.rewindMode ? "rewind" : "objects", date: dataPayload.date, request_id: newRequestID, diff --git a/web-app/tests/permissions-B/bucketWritePrefixOnly.ts b/web-app/tests/permissions-B/bucketWritePrefixOnly.ts index e6c8050a6..7f2dcb441 100644 --- a/web-app/tests/permissions-B/bucketWritePrefixOnly.ts +++ b/web-app/tests/permissions-B/bucketWritePrefixOnly.ts @@ -54,7 +54,7 @@ test const uploadButton = elements.uploadButton; await t .useRole(roles.bucketWritePrefixOnly) - .navigateTo("http://localhost:9090/browser/testcafe/d3JpdGU=") + .navigateTo("http://localhost:9090/browser/testcafe/write") .click(uploadButton) .expect( Selector("div")