Use automatic URI encoding (#3352)
This commit is contained in:
2
Makefile
2
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
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
5
generator.config.js
Normal file
5
generator.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
hooks: {
|
||||
onInsertPathParam: (paramName) => `encodeURIComponent(${paramName})`,
|
||||
},
|
||||
};
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
17
semgrep.yaml
17
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(...)
|
||||
|
||||
@@ -1987,7 +1987,7 @@ export class Api<
|
||||
*/
|
||||
bucketInfo: (name: string, params: RequestParams = {}) =>
|
||||
this.request<Bucket, ApiError>({
|
||||
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<void, ApiError>({
|
||||
path: `/buckets/${name}`,
|
||||
path: `/buckets/${encodeURIComponent(name)}`,
|
||||
method: "DELETE",
|
||||
secure: true,
|
||||
...params,
|
||||
@@ -2025,7 +2025,7 @@ export class Api<
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<GetBucketRetentionConfig, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<ListObjectsResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<File, ApiError>({
|
||||
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<File, ApiError>({
|
||||
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<IamEntity, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<Metadata, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<Bucket, ApiError>({
|
||||
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<BucketQuota, ApiError>({
|
||||
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<Bucket, ApiError>({
|
||||
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<ListBucketEventsResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<BucketReplicationResponse, ApiError>({
|
||||
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<BucketReplicationRule, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<BucketVersioningResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<BucketObLockingResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<BucketEncryptionInfo, ApiError>({
|
||||
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<BucketLifecycleResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<RewindResponse, ApiError>({
|
||||
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<ServiceAccount, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<User, ApiError>({
|
||||
path: `/user/${name}`,
|
||||
path: `/user/${encodeURIComponent(name)}`,
|
||||
method: "GET",
|
||||
secure: true,
|
||||
format: "json",
|
||||
@@ -3300,7 +3300,7 @@ export class Api<
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<User, ApiError>({
|
||||
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<void, ApiError>({
|
||||
path: `/user/${name}`,
|
||||
path: `/user/${encodeURIComponent(name)}`,
|
||||
method: "DELETE",
|
||||
secure: true,
|
||||
...params,
|
||||
@@ -3341,7 +3341,7 @@ export class Api<
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<User, ApiError>({
|
||||
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<AUserPolicyResponse, ApiError>({
|
||||
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<ServiceAccounts, ApiError>({
|
||||
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<ServiceAccountCreds, ApiError>({
|
||||
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<ServiceAccountCreds, ApiError>({
|
||||
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<Group, ApiError>({
|
||||
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<void, ApiError>({
|
||||
path: `/group/${name}`,
|
||||
path: `/group/${encodeURIComponent(name)}`,
|
||||
method: "DELETE",
|
||||
secure: true,
|
||||
...params,
|
||||
@@ -3574,7 +3574,7 @@ export class Api<
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<Group, ApiError>({
|
||||
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<SelectedUsers, ApiError>({
|
||||
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<SelectedUsers, ApiError>({
|
||||
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<ListPoliciesResponse, ApiError>({
|
||||
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<boolean, ApiError>({
|
||||
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<ListAccessRulesResponse, ApiError>({
|
||||
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<boolean, ApiError>({
|
||||
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<SelectedUsers, ApiError>({
|
||||
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<Policy, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<Configuration[], ApiError>({
|
||||
path: `/configs/${name}`,
|
||||
path: `/configs/${encodeURIComponent(name)}`,
|
||||
method: "GET",
|
||||
secure: true,
|
||||
format: "json",
|
||||
@@ -3929,7 +3929,7 @@ export class Api<
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<SetConfigResponse, ApiError>({
|
||||
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<SetConfigResponse, ApiError>({
|
||||
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<WidgetDetails, ApiError>({
|
||||
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<Tier, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<RemoteBucket, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<KmsKeyStatusResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<KmsGetPolicyResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<KmsDescribePolicyResponse, ApiError>({
|
||||
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<void, ApiError>({
|
||||
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<KmsDescribeIdentityResponse, ApiError>({
|
||||
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<SetIDPResponse, ApiError>({
|
||||
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<IdpListConfigurationsResponse, ApiError>({
|
||||
path: `/idp/${type}`,
|
||||
path: `/idp/${encodeURIComponent(type)}`,
|
||||
method: "GET",
|
||||
secure: true,
|
||||
format: "json",
|
||||
@@ -5134,7 +5134,7 @@ export class Api<
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<IdpServerConfiguration, ApiError>({
|
||||
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<SetIDPResponse, ApiError>({
|
||||
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<SetIDPResponse, ApiError>({
|
||||
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<File, ApiError>({
|
||||
path: `/download-shared-object/${url}`,
|
||||
path: `/download-shared-object/${encodeURIComponent(url)}`,
|
||||
method: "GET",
|
||||
...params,
|
||||
}),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)}`);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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}/`,
|
||||
)}`;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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={
|
||||
<Fragment>
|
||||
Are you sure you want to delete all the non-current versions for:{" "}
|
||||
<b>{decodeURLString(selectedObject)}</b>? <br />
|
||||
<b>{selectedObject}</b>? <br />
|
||||
{canBypass && (
|
||||
<Fragment>
|
||||
<div
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { ErrorResponseHandler } from "../../../../../../common/types";
|
||||
import { decodeURLString } from "../../../../../../common/utils";
|
||||
import ConfirmDialog from "../../../../Common/ModalWrapper/ConfirmDialog";
|
||||
import useApi from "../../../../Common/Hooks/useApi";
|
||||
import { ConfirmDeleteIcon, Switch } from "mds";
|
||||
@@ -76,13 +75,12 @@ const DeleteObject = ({
|
||||
return null;
|
||||
}
|
||||
const onConfirmDelete = () => {
|
||||
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={
|
||||
<Fragment>
|
||||
Are you sure you want to delete: <br />
|
||||
<b>{decodeURLString(selectedObject)}</b>{" "}
|
||||
<b>{selectedObject}</b>{" "}
|
||||
{selectedVersion !== "" ? (
|
||||
<Fragment>
|
||||
<br />
|
||||
|
||||
@@ -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 <b>{decodeURLString(inspectPath)}</b>?{" "}
|
||||
<br />
|
||||
Would you like to encrypt <b>{inspectPath}</b>? <br />
|
||||
<Switch
|
||||
label={"Encrypt"}
|
||||
indicatorLabels={["Yes", "No"]}
|
||||
|
||||
@@ -48,11 +48,7 @@ import { useSelector } from "react-redux";
|
||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import { DateTime } from "luxon";
|
||||
import {
|
||||
decodeURLString,
|
||||
encodeURLString,
|
||||
niceBytesInt,
|
||||
} from "../../../../../../common/utils";
|
||||
import { niceBytesInt } from "../../../../../../common/utils";
|
||||
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
|
||||
import { AllowedPreviews, previewObjectType } from "../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../../common/types";
|
||||
@@ -235,10 +231,10 @@ const ListObjects = () => {
|
||||
|
||||
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 = () => {
|
||||
>
|
||||
<BrowserBreadcrumbs
|
||||
bucketName={bucketName}
|
||||
internalPaths={pageTitle}
|
||||
internalPaths={internalPaths}
|
||||
additionalOptions={
|
||||
!isVersioningApplied || rewindEnabled ? null : (
|
||||
<Checkbox
|
||||
|
||||
@@ -19,7 +19,6 @@ import { listModeColumns, rewindModeColumns } from "./ListObjectsHelpers";
|
||||
import { useSelector } from "react-redux";
|
||||
import { AppState, useAppDispatch } from "../../../../../../store";
|
||||
import { selFeatures } from "../../../../consoleSlice";
|
||||
import { encodeURLString } from "../../../../../../common/utils";
|
||||
import {
|
||||
setLoadingVersions,
|
||||
setObjectDetailsView,
|
||||
@@ -111,18 +110,13 @@ const ListObjectsTable = () => {
|
||||
|
||||
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[] = [
|
||||
{
|
||||
|
||||
@@ -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<any | null>(null);
|
||||
const [loadMetadata, setLoadingMetadata] = useState<boolean>(false);
|
||||
|
||||
const internalPathsDecoded = decodeURLString(internalPaths) || "";
|
||||
const internalPathsDecoded = internalPaths || "";
|
||||
const allPathData = internalPathsDecoded.split("/");
|
||||
const currentItem = allPathData.pop() || "";
|
||||
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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 || "",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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` : "",
|
||||
})
|
||||
|
||||
@@ -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<string>("");
|
||||
const [deleteLabel, setDeleteLabel] = useState<string>("");
|
||||
|
||||
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(() => {
|
||||
|
||||
@@ -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 && (
|
||||
<DeleteSelectedVersions
|
||||
selectedBucket={bucketName}
|
||||
selectedObject={decodeURLString(internalPaths)}
|
||||
selectedObject={internalPaths}
|
||||
deleteOpen={delSelectedVOpen}
|
||||
selectedVersions={selectedItems}
|
||||
closeDeleteModalAndRefresh={closeSelectedVersions}
|
||||
@@ -383,7 +381,7 @@ const VersionsNavigator = ({
|
||||
<Grid item xs={12}>
|
||||
<BrowserBreadcrumbs
|
||||
bucketName={bucketName}
|
||||
internalPaths={decodeURLString(internalPaths)}
|
||||
internalPaths={internalPaths}
|
||||
hidePathButton={true}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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<string>("");
|
||||
const [currentTab, setCurrentTab] = useState<string>("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 ? (
|
||||
<SetPolicy
|
||||
open={policyOpen}
|
||||
selectedGroups={[groupName]}
|
||||
selectedGroups={[params.groupName || ""]}
|
||||
selectedUser={null}
|
||||
closeModalAndRefresh={() => {
|
||||
setPolicyOpen(false);
|
||||
@@ -344,7 +345,7 @@ const GroupsDetails = () => {
|
||||
|
||||
{usersOpen ? (
|
||||
<AddGroupMember
|
||||
selectedGroup={groupName}
|
||||
selectedGroup={params.groupName}
|
||||
onSaveClick={() => {}}
|
||||
title={memberActionText}
|
||||
groupStatus={groupEnabled}
|
||||
@@ -360,7 +361,7 @@ const GroupsDetails = () => {
|
||||
{deleteOpen && (
|
||||
<DeleteGroup
|
||||
deleteOpen={deleteOpen}
|
||||
selectedGroups={[groupName]}
|
||||
selectedGroups={[params.groupName || ""]}
|
||||
closeDeleteModalAndRefresh={(isDelSuccess: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
if (isDelSuccess) {
|
||||
@@ -388,7 +389,7 @@ const GroupsDetails = () => {
|
||||
<GroupsIcon width={40} />
|
||||
</Fragment>
|
||||
}
|
||||
title={groupName}
|
||||
title={params.groupName || ""}
|
||||
subTitle={null}
|
||||
bottomBorder
|
||||
actions={
|
||||
|
||||
@@ -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("/")}/`)}`
|
||||
: ""
|
||||
}`,
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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()}`,
|
||||
);
|
||||
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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<string[]>([]);
|
||||
const [addLoading, setAddLoading] = useState<boolean>(false);
|
||||
|
||||
const policyName = decodeURLString(params.policyName || "");
|
||||
const policyName = params.policyName || "";
|
||||
|
||||
const [policyDefinition, setPolicyDefinition] = useState<string>("");
|
||||
const [loadingPolicy, setLoadingPolicy] = useState<boolean>(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 = [
|
||||
|
||||
@@ -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(","));
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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<NewServiceAccount | null>(null);
|
||||
const [policyJSON, setPolicyJSON] = useState<string>("");
|
||||
|
||||
const userName = decodeURLString(params.userName || "");
|
||||
const userName = params.userName || "";
|
||||
|
||||
const [name, setName] = useState<string>("");
|
||||
const [description, setDescription] = useState<string>("");
|
||||
@@ -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={
|
||||
<BackLink
|
||||
onClick={() =>
|
||||
navigate(`${IAM_PAGES.USERS}/${encodeURLString(userName)}`)
|
||||
navigate(`${IAM_PAGES.USERS}/${encodeURIComponent(userName)}`)
|
||||
}
|
||||
label={"User Details - " + userName}
|
||||
/>
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
@@ -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)}`,
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
)}`,
|
||||
);
|
||||
|
||||
@@ -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={<AddIcon />}
|
||||
onClick={() => {
|
||||
navigate(
|
||||
`/identity/users/new-user-sa/${encodeURLString(user)}`,
|
||||
`/identity/users/new-user-sa/${encodeURIComponent(user)}`,
|
||||
);
|
||||
}}
|
||||
disabled={!hasPolicy}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user