Use automatic URI encoding (#3352)
This commit is contained in:
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user