github.com/minio/console@v1.3.0/api/user_buckets.go (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package api
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/minio/minio-go/v7"
    29  
    30  	"github.com/minio/madmin-go/v3"
    31  	"github.com/minio/mc/cmd"
    32  	"github.com/minio/mc/pkg/probe"
    33  	"github.com/minio/minio-go/v7/pkg/sse"
    34  	"github.com/minio/minio-go/v7/pkg/tags"
    35  
    36  	"github.com/go-openapi/runtime/middleware"
    37  	"github.com/go-openapi/swag"
    38  	"github.com/minio/console/api/operations"
    39  	bucketApi "github.com/minio/console/api/operations/bucket"
    40  	"github.com/minio/console/models"
    41  	"github.com/minio/console/pkg/auth/token"
    42  	"github.com/minio/minio-go/v7/pkg/policy"
    43  	"github.com/minio/minio-go/v7/pkg/replication"
    44  	minioIAMPolicy "github.com/minio/pkg/v2/policy"
    45  )
    46  
    47  func registerBucketsHandlers(api *operations.ConsoleAPI) {
    48  	// list buckets
    49  	api.BucketListBucketsHandler = bucketApi.ListBucketsHandlerFunc(func(params bucketApi.ListBucketsParams, session *models.Principal) middleware.Responder {
    50  		listBucketsResponse, err := getListBucketsResponse(session, params)
    51  		if err != nil {
    52  			return bucketApi.NewListBucketsDefault(err.Code).WithPayload(err.APIError)
    53  		}
    54  		return bucketApi.NewListBucketsOK().WithPayload(listBucketsResponse)
    55  	})
    56  	// make bucket
    57  	api.BucketMakeBucketHandler = bucketApi.MakeBucketHandlerFunc(func(params bucketApi.MakeBucketParams, session *models.Principal) middleware.Responder {
    58  		makeBucketResponse, err := getMakeBucketResponse(session, params)
    59  		if err != nil {
    60  			return bucketApi.NewMakeBucketDefault(err.Code).WithPayload(err.APIError)
    61  		}
    62  		return bucketApi.NewMakeBucketOK().WithPayload(makeBucketResponse)
    63  	})
    64  	// delete bucket
    65  	api.BucketDeleteBucketHandler = bucketApi.DeleteBucketHandlerFunc(func(params bucketApi.DeleteBucketParams, session *models.Principal) middleware.Responder {
    66  		if err := getDeleteBucketResponse(session, params); err != nil {
    67  			return bucketApi.NewMakeBucketDefault(err.Code).WithPayload(err.APIError)
    68  		}
    69  		return bucketApi.NewDeleteBucketNoContent()
    70  	})
    71  	// get bucket info
    72  	api.BucketBucketInfoHandler = bucketApi.BucketInfoHandlerFunc(func(params bucketApi.BucketInfoParams, session *models.Principal) middleware.Responder {
    73  		bucketInfoResp, err := getBucketInfoResponse(session, params)
    74  		if err != nil {
    75  			return bucketApi.NewBucketInfoDefault(err.Code).WithPayload(err.APIError)
    76  		}
    77  
    78  		return bucketApi.NewBucketInfoOK().WithPayload(bucketInfoResp)
    79  	})
    80  	// set bucket policy
    81  	api.BucketBucketSetPolicyHandler = bucketApi.BucketSetPolicyHandlerFunc(func(params bucketApi.BucketSetPolicyParams, session *models.Principal) middleware.Responder {
    82  		bucketSetPolicyResp, err := getBucketSetPolicyResponse(session, params)
    83  		if err != nil {
    84  			return bucketApi.NewBucketSetPolicyDefault(err.Code).WithPayload(err.APIError)
    85  		}
    86  		return bucketApi.NewBucketSetPolicyOK().WithPayload(bucketSetPolicyResp)
    87  	})
    88  	// set bucket tags
    89  	api.BucketPutBucketTagsHandler = bucketApi.PutBucketTagsHandlerFunc(func(params bucketApi.PutBucketTagsParams, session *models.Principal) middleware.Responder {
    90  		err := getPutBucketTagsResponse(session, params)
    91  		if err != nil {
    92  			return bucketApi.NewPutBucketTagsDefault(err.Code).WithPayload(err.APIError)
    93  		}
    94  		return bucketApi.NewPutBucketTagsOK()
    95  	})
    96  	// get bucket versioning
    97  	api.BucketGetBucketVersioningHandler = bucketApi.GetBucketVersioningHandlerFunc(func(params bucketApi.GetBucketVersioningParams, session *models.Principal) middleware.Responder {
    98  		getBucketVersioning, err := getBucketVersionedResponse(session, params)
    99  		if err != nil {
   100  			return bucketApi.NewGetBucketVersioningDefault(err.Code).WithPayload(err.APIError)
   101  		}
   102  		return bucketApi.NewGetBucketVersioningOK().WithPayload(getBucketVersioning)
   103  	})
   104  	// update bucket versioning
   105  	api.BucketSetBucketVersioningHandler = bucketApi.SetBucketVersioningHandlerFunc(func(params bucketApi.SetBucketVersioningParams, session *models.Principal) middleware.Responder {
   106  		err := setBucketVersioningResponse(session, params)
   107  		if err != nil {
   108  			return bucketApi.NewSetBucketVersioningDefault(err.Code).WithPayload(err.APIError)
   109  		}
   110  		return bucketApi.NewSetBucketVersioningCreated()
   111  	})
   112  	// get bucket replication
   113  	api.BucketGetBucketReplicationHandler = bucketApi.GetBucketReplicationHandlerFunc(func(params bucketApi.GetBucketReplicationParams, session *models.Principal) middleware.Responder {
   114  		getBucketReplication, err := getBucketReplicationResponse(session, params)
   115  		if err != nil {
   116  			return bucketApi.NewGetBucketReplicationDefault(err.Code).WithPayload(err.APIError)
   117  		}
   118  		return bucketApi.NewGetBucketReplicationOK().WithPayload(getBucketReplication)
   119  	})
   120  	// get single bucket replication rule
   121  	api.BucketGetBucketReplicationRuleHandler = bucketApi.GetBucketReplicationRuleHandlerFunc(func(params bucketApi.GetBucketReplicationRuleParams, session *models.Principal) middleware.Responder {
   122  		getBucketReplicationRule, err := getBucketReplicationRuleResponse(session, params)
   123  		if err != nil {
   124  			return bucketApi.NewGetBucketReplicationRuleDefault(err.Code).WithPayload(err.APIError)
   125  		}
   126  		return bucketApi.NewGetBucketReplicationRuleOK().WithPayload(getBucketReplicationRule)
   127  	})
   128  
   129  	// enable bucket encryption
   130  	api.BucketEnableBucketEncryptionHandler = bucketApi.EnableBucketEncryptionHandlerFunc(func(params bucketApi.EnableBucketEncryptionParams, session *models.Principal) middleware.Responder {
   131  		if err := enableBucketEncryptionResponse(session, params); err != nil {
   132  			return bucketApi.NewEnableBucketEncryptionDefault(err.Code).WithPayload(err.APIError)
   133  		}
   134  		return bucketApi.NewEnableBucketEncryptionOK()
   135  	})
   136  	// disable bucket encryption
   137  	api.BucketDisableBucketEncryptionHandler = bucketApi.DisableBucketEncryptionHandlerFunc(func(params bucketApi.DisableBucketEncryptionParams, session *models.Principal) middleware.Responder {
   138  		if err := disableBucketEncryptionResponse(session, params); err != nil {
   139  			return bucketApi.NewDisableBucketEncryptionDefault(err.Code).WithPayload(err.APIError)
   140  		}
   141  		return bucketApi.NewDisableBucketEncryptionOK()
   142  	})
   143  	// get bucket encryption info
   144  	api.BucketGetBucketEncryptionInfoHandler = bucketApi.GetBucketEncryptionInfoHandlerFunc(func(params bucketApi.GetBucketEncryptionInfoParams, session *models.Principal) middleware.Responder {
   145  		response, err := getBucketEncryptionInfoResponse(session, params)
   146  		if err != nil {
   147  			return bucketApi.NewGetBucketEncryptionInfoDefault(err.Code).WithPayload(err.APIError)
   148  		}
   149  		return bucketApi.NewGetBucketEncryptionInfoOK().WithPayload(response)
   150  	})
   151  	// set bucket retention config
   152  	api.BucketSetBucketRetentionConfigHandler = bucketApi.SetBucketRetentionConfigHandlerFunc(func(params bucketApi.SetBucketRetentionConfigParams, session *models.Principal) middleware.Responder {
   153  		if err := getSetBucketRetentionConfigResponse(session, params); err != nil {
   154  			return bucketApi.NewSetBucketRetentionConfigDefault(err.Code).WithPayload(err.APIError)
   155  		}
   156  		return bucketApi.NewSetBucketRetentionConfigOK()
   157  	})
   158  	// get bucket retention config
   159  	api.BucketGetBucketRetentionConfigHandler = bucketApi.GetBucketRetentionConfigHandlerFunc(func(params bucketApi.GetBucketRetentionConfigParams, session *models.Principal) middleware.Responder {
   160  		response, err := getBucketRetentionConfigResponse(session, params)
   161  		if err != nil {
   162  			return bucketApi.NewGetBucketRetentionConfigDefault(err.Code).WithPayload(err.APIError)
   163  		}
   164  		return bucketApi.NewGetBucketRetentionConfigOK().WithPayload(response)
   165  	})
   166  	// get bucket object locking status
   167  	api.BucketGetBucketObjectLockingStatusHandler = bucketApi.GetBucketObjectLockingStatusHandlerFunc(func(params bucketApi.GetBucketObjectLockingStatusParams, session *models.Principal) middleware.Responder {
   168  		getBucketObjectLockingStatus, err := getBucketObjectLockingResponse(session, params)
   169  		if err != nil {
   170  			return bucketApi.NewGetBucketObjectLockingStatusDefault(err.Code).WithPayload(err.APIError)
   171  		}
   172  		return bucketApi.NewGetBucketObjectLockingStatusOK().WithPayload(getBucketObjectLockingStatus)
   173  	})
   174  	// get objects rewind for a bucket
   175  	api.BucketGetBucketRewindHandler = bucketApi.GetBucketRewindHandlerFunc(func(params bucketApi.GetBucketRewindParams, session *models.Principal) middleware.Responder {
   176  		getBucketRewind, err := getBucketRewindResponse(session, params)
   177  		if err != nil {
   178  			return bucketApi.NewGetBucketRewindDefault(err.Code).WithPayload(err.APIError)
   179  		}
   180  		return bucketApi.NewGetBucketRewindOK().WithPayload(getBucketRewind)
   181  	})
   182  	// get max allowed share link expiration time
   183  	api.BucketGetMaxShareLinkExpHandler = bucketApi.GetMaxShareLinkExpHandlerFunc(func(params bucketApi.GetMaxShareLinkExpParams, session *models.Principal) middleware.Responder {
   184  		val, err := getMaxShareLinkExpirationResponse(session, params)
   185  		if err != nil {
   186  			return bucketApi.NewGetMaxShareLinkExpDefault(err.Code).WithPayload(err.APIError)
   187  		}
   188  		return bucketApi.NewGetMaxShareLinkExpOK().WithPayload(val)
   189  	})
   190  }
   191  
   192  type VersionState string
   193  
   194  const (
   195  	VersionEnable  VersionState = "enable"
   196  	VersionSuspend VersionState = "suspend"
   197  )
   198  
   199  // removeBucket deletes a bucket
   200  func doSetVersioning(ctx context.Context, client MCClient, state VersionState, excludePrefix []string, excludeFolders bool) error {
   201  	err := client.setVersioning(ctx, string(state), excludePrefix, excludeFolders)
   202  	if err != nil {
   203  		return err.Cause
   204  	}
   205  
   206  	return nil
   207  }
   208  
   209  func setBucketVersioningResponse(session *models.Principal, params bucketApi.SetBucketVersioningParams) *CodedAPIError {
   210  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   211  	defer cancel()
   212  
   213  	bucketName := params.BucketName
   214  	s3Client, err := newS3BucketClient(session, bucketName, "", getClientIP(params.HTTPRequest))
   215  	if err != nil {
   216  		return ErrorWithContext(ctx, err)
   217  	}
   218  	// create a mc S3Client interface implementation
   219  	// defining the client to be used
   220  	amcClient := mcClient{client: s3Client}
   221  
   222  	versioningState := VersionSuspend
   223  
   224  	if params.Body.Enabled {
   225  		versioningState = VersionEnable
   226  	}
   227  
   228  	var excludePrefixes []string
   229  
   230  	if params.Body.ExcludePrefixes != nil {
   231  		excludePrefixes = params.Body.ExcludePrefixes
   232  	}
   233  
   234  	excludeFolders := params.Body.ExcludeFolders
   235  
   236  	if err := doSetVersioning(ctx, amcClient, versioningState, excludePrefixes, excludeFolders); err != nil {
   237  		return ErrorWithContext(ctx, fmt.Errorf("error setting versioning for bucket: %s", err))
   238  	}
   239  	return nil
   240  }
   241  
   242  func getBucketReplicationResponse(session *models.Principal, params bucketApi.GetBucketReplicationParams) (*models.BucketReplicationResponse, *CodedAPIError) {
   243  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   244  	defer cancel()
   245  
   246  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   247  	if err != nil {
   248  		return nil, ErrorWithContext(ctx, err)
   249  	}
   250  	// create a minioClient interface implementation
   251  	// defining the client to be used
   252  	minioClient := minioClient{client: mClient}
   253  
   254  	// we will tolerate this call failing
   255  	res, err := minioClient.getBucketReplication(ctx, params.BucketName)
   256  	if err != nil {
   257  		ErrorWithContext(ctx, err)
   258  	}
   259  
   260  	var rules []*models.BucketReplicationRule
   261  
   262  	for _, rule := range res.Rules {
   263  		repDelMarkerStatus := false
   264  		if rule.DeleteMarkerReplication.Status == "enable" {
   265  			repDelMarkerStatus = true
   266  		}
   267  		repDelStatus := false
   268  		if rule.DeleteReplication.Status == "enable" {
   269  			repDelMarkerStatus = true
   270  		}
   271  
   272  		rules = append(rules, &models.BucketReplicationRule{
   273  			DeleteMarkerReplication: repDelMarkerStatus,
   274  			DeletesReplication:      repDelStatus,
   275  			Destination:             &models.BucketReplicationDestination{Bucket: rule.Destination.Bucket},
   276  			Tags:                    rule.Tags(),
   277  			Prefix:                  rule.Prefix(),
   278  			ID:                      rule.ID,
   279  			Priority:                int32(rule.Priority),
   280  			Status:                  string(rule.Status),
   281  			StorageClass:            rule.Destination.StorageClass,
   282  		})
   283  	}
   284  
   285  	// serialize output
   286  	bucketRResponse := &models.BucketReplicationResponse{
   287  		Rules: rules,
   288  	}
   289  	return bucketRResponse, nil
   290  }
   291  
   292  func getBucketReplicationRuleResponse(session *models.Principal, params bucketApi.GetBucketReplicationRuleParams) (*models.BucketReplicationRule, *CodedAPIError) {
   293  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   294  	defer cancel()
   295  
   296  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   297  	if err != nil {
   298  		return nil, ErrorWithContext(ctx, err)
   299  	}
   300  	// create a minioClient interface implementation
   301  
   302  	// defining the client to be used
   303  	minioClient := minioClient{client: mClient}
   304  
   305  	replicationRules, err := minioClient.getBucketReplication(ctx, params.BucketName)
   306  	if err != nil {
   307  		return nil, ErrorWithContext(ctx, err)
   308  	}
   309  
   310  	var foundRule replication.Rule
   311  	found := false
   312  
   313  	for i := range replicationRules.Rules {
   314  		if replicationRules.Rules[i].ID == params.RuleID {
   315  			foundRule = replicationRules.Rules[i]
   316  			found = true
   317  			break
   318  		}
   319  	}
   320  
   321  	if !found {
   322  		return nil, ErrorWithContext(ctx, errors.New("no rule is set with this ID"))
   323  	}
   324  
   325  	repDelMarkerStatus := false
   326  	if foundRule.DeleteMarkerReplication.Status == "Enabled" {
   327  		repDelMarkerStatus = true
   328  	}
   329  	repDelStatus := false
   330  	if foundRule.DeleteReplication.Status == "Enabled" {
   331  		repDelStatus = true
   332  	}
   333  	existingObjects := false
   334  	if foundRule.ExistingObjectReplication.Status == "Enabled" {
   335  		existingObjects = true
   336  	}
   337  	metadataModifications := false
   338  	if foundRule.SourceSelectionCriteria.ReplicaModifications.Status == "Enabled" {
   339  		metadataModifications = true
   340  	}
   341  
   342  	returnRule := &models.BucketReplicationRule{
   343  		DeleteMarkerReplication: repDelMarkerStatus,
   344  		DeletesReplication:      repDelStatus,
   345  		Destination:             &models.BucketReplicationDestination{Bucket: foundRule.Destination.Bucket},
   346  		Tags:                    foundRule.Tags(),
   347  		Prefix:                  foundRule.Prefix(),
   348  		ID:                      foundRule.ID,
   349  		Priority:                int32(foundRule.Priority),
   350  		Status:                  string(foundRule.Status),
   351  		StorageClass:            foundRule.Destination.StorageClass,
   352  		ExistingObjects:         existingObjects,
   353  		MetadataReplication:     metadataModifications,
   354  	}
   355  
   356  	return returnRule, nil
   357  }
   358  
   359  func getBucketVersionedResponse(session *models.Principal, params bucketApi.GetBucketVersioningParams) (*models.BucketVersioningResponse, *CodedAPIError) {
   360  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   361  	defer cancel()
   362  
   363  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   364  	if err != nil {
   365  		return nil, ErrorWithContext(ctx, err)
   366  	}
   367  
   368  	// create a minioClient interface implementation
   369  	// defining the client to be used
   370  	minioClient := minioClient{client: mClient}
   371  
   372  	// we will tolerate this call failing
   373  	res, err := minioClient.getBucketVersioning(ctx, params.BucketName)
   374  	if err != nil {
   375  		ErrorWithContext(ctx, fmt.Errorf("error versioning bucket: %v", err))
   376  	}
   377  
   378  	excludedPrefixes := make([]*models.BucketVersioningResponseExcludedPrefixesItems0, len(res.ExcludedPrefixes))
   379  	for i, v := range res.ExcludedPrefixes {
   380  		excludedPrefixes[i] = &models.BucketVersioningResponseExcludedPrefixesItems0{
   381  			Prefix: v.Prefix,
   382  		}
   383  	}
   384  
   385  	// serialize output
   386  	bucketVResponse := &models.BucketVersioningResponse{
   387  		ExcludeFolders:   res.ExcludeFolders,
   388  		ExcludedPrefixes: excludedPrefixes,
   389  		MFADelete:        res.MFADelete,
   390  		Status:           res.Status,
   391  	}
   392  	return bucketVResponse, nil
   393  }
   394  
   395  // getAccountBuckets fetches a list of all buckets allowed to that particular client from MinIO Servers
   396  func getAccountBuckets(ctx context.Context, client MinioAdmin) ([]*models.Bucket, error) {
   397  	info, err := client.AccountInfo(ctx)
   398  	if err != nil {
   399  		return []*models.Bucket{}, err
   400  	}
   401  	bucketInfos := []*models.Bucket{}
   402  	for _, bucket := range info.Buckets {
   403  		bucketElem := &models.Bucket{
   404  			CreationDate: bucket.Created.Format(time.RFC3339),
   405  			Details: &models.BucketDetails{
   406  				Quota: nil,
   407  			},
   408  			RwAccess: &models.BucketRwAccess{
   409  				Read:  bucket.Access.Read,
   410  				Write: bucket.Access.Write,
   411  			},
   412  			Name:    swag.String(bucket.Name),
   413  			Objects: int64(bucket.Objects),
   414  			Size:    int64(bucket.Size),
   415  		}
   416  
   417  		if bucket.Details != nil {
   418  			if bucket.Details.Tagging != nil {
   419  				bucketElem.Details.Tags = bucket.Details.Tagging.ToMap()
   420  			}
   421  
   422  			bucketElem.Details.Locking = bucket.Details.Locking
   423  			bucketElem.Details.Replication = bucket.Details.Replication
   424  			bucketElem.Details.Versioning = bucket.Details.Versioning
   425  			bucketElem.Details.VersioningSuspended = bucket.Details.VersioningSuspended
   426  			if bucket.Details.Quota != nil {
   427  				bucketElem.Details.Quota = &models.BucketDetailsQuota{
   428  					Quota: int64(bucket.Details.Quota.Quota),
   429  					Type:  string(bucket.Details.Quota.Type),
   430  				}
   431  			}
   432  		}
   433  
   434  		bucketInfos = append(bucketInfos, bucketElem)
   435  	}
   436  	return bucketInfos, nil
   437  }
   438  
   439  // getListBucketsResponse performs listBuckets() and serializes it to the handler's output
   440  func getListBucketsResponse(session *models.Principal, params bucketApi.ListBucketsParams) (*models.ListBucketsResponse, *CodedAPIError) {
   441  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   442  	defer cancel()
   443  
   444  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   445  	if err != nil {
   446  		return nil, ErrorWithContext(ctx, err)
   447  	}
   448  	// create a minioClient interface implementation
   449  	// defining the client to be used
   450  	adminClient := AdminClient{Client: mAdmin}
   451  	buckets, err := getAccountBuckets(ctx, adminClient)
   452  	if err != nil {
   453  		return nil, ErrorWithContext(ctx, err)
   454  	}
   455  
   456  	// serialize output
   457  	listBucketsResponse := &models.ListBucketsResponse{
   458  		Buckets: buckets,
   459  		Total:   int64(len(buckets)),
   460  	}
   461  	return listBucketsResponse, nil
   462  }
   463  
   464  // makeBucket creates a bucket for an specific minio client
   465  func makeBucket(ctx context.Context, client MinioClient, bucketName string, objectLocking bool) error {
   466  	// creates a new bucket with bucketName with a context to control cancellations and timeouts.
   467  	return client.makeBucketWithContext(ctx, bucketName, "", objectLocking)
   468  }
   469  
   470  // getMakeBucketResponse performs makeBucket() to create a bucket with its access policy
   471  func getMakeBucketResponse(session *models.Principal, params bucketApi.MakeBucketParams) (*models.MakeBucketsResponse, *CodedAPIError) {
   472  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   473  	defer cancel()
   474  	// bucket request needed to proceed
   475  	br := params.Body
   476  	if br == nil {
   477  		return nil, ErrorWithContext(ctx, ErrBucketBodyNotInRequest)
   478  	}
   479  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   480  	if err != nil {
   481  		return nil, ErrorWithContext(ctx, err)
   482  	}
   483  	// create a minioClient interface implementation
   484  	// defining the client to be used
   485  	minioClient := minioClient{client: mClient}
   486  
   487  	// if we need retention, then object locking needs to be enabled
   488  	if br.Retention != nil {
   489  		br.Locking = true
   490  	}
   491  
   492  	if err := makeBucket(ctx, minioClient, *br.Name, br.Locking); err != nil {
   493  		return nil, ErrorWithContext(ctx, err)
   494  	}
   495  
   496  	// make sure to delete bucket if an errors occurs after bucket was created
   497  	defer func() {
   498  		if err != nil {
   499  			ErrorWithContext(ctx, fmt.Errorf("error creating bucket: %v", err))
   500  			if err := removeBucket(minioClient, *br.Name); err != nil {
   501  				ErrorWithContext(ctx, fmt.Errorf("error removing bucket: %v", err))
   502  			}
   503  		}
   504  	}()
   505  
   506  	versioningEnabled := false
   507  
   508  	if br.Versioning != nil && br.Versioning.Enabled {
   509  		versioningEnabled = true
   510  	}
   511  
   512  	// enable versioning if indicated or retention enabled
   513  	if versioningEnabled || br.Retention != nil {
   514  		s3Client, err := newS3BucketClient(session, *br.Name, "", getClientIP(params.HTTPRequest))
   515  		if err != nil {
   516  			return nil, ErrorWithContext(ctx, err)
   517  		}
   518  		// create a mc S3Client interface implementation
   519  		// defining the client to be used
   520  		amcClient := mcClient{client: s3Client}
   521  
   522  		excludePrefixes := []string{}
   523  		excludeFolders := false
   524  
   525  		if br.Versioning.ExcludeFolders && !br.Locking {
   526  			excludeFolders = true
   527  		}
   528  
   529  		if br.Versioning.ExcludePrefixes != nil && !br.Locking {
   530  			excludePrefixes = br.Versioning.ExcludePrefixes
   531  		}
   532  
   533  		if err = doSetVersioning(ctx, amcClient, VersionEnable, excludePrefixes, excludeFolders); err != nil {
   534  			return nil, ErrorWithContext(ctx, fmt.Errorf("error setting versioning for bucket: %s", err))
   535  		}
   536  	}
   537  
   538  	// if it has support for
   539  	if br.Quota != nil && br.Quota.Enabled != nil && *br.Quota.Enabled {
   540  		mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   541  		if err != nil {
   542  			return nil, ErrorWithContext(ctx, err)
   543  		}
   544  		// create a minioClient interface implementation
   545  		// defining the client to be used
   546  		adminClient := AdminClient{Client: mAdmin}
   547  		// we will tolerate this call failing
   548  		if err := setBucketQuota(ctx, &adminClient, br.Name, br.Quota); err != nil {
   549  			ErrorWithContext(ctx, fmt.Errorf("error versioning bucket: %v", err))
   550  		}
   551  	}
   552  
   553  	// Set Bucket Retention Configuration if defined
   554  	if br.Retention != nil {
   555  		err = setBucketRetentionConfig(ctx, minioClient, *br.Name, *br.Retention.Mode, *br.Retention.Unit, br.Retention.Validity)
   556  		if err != nil {
   557  			return nil, ErrorWithContext(ctx, err)
   558  		}
   559  	}
   560  	return &models.MakeBucketsResponse{BucketName: *br.Name}, nil
   561  }
   562  
   563  // setBucketAccessPolicy set the access permissions on an existing bucket.
   564  func setBucketAccessPolicy(ctx context.Context, client MinioClient, bucketName string, access models.BucketAccess, policyDefinition string) error {
   565  	if strings.TrimSpace(bucketName) == "" {
   566  		return fmt.Errorf("error: bucket name not present")
   567  	}
   568  	if strings.TrimSpace(string(access)) == "" {
   569  		return fmt.Errorf("error: bucket access not present")
   570  	}
   571  	// Prepare policyJSON corresponding to the access type
   572  	if access != models.BucketAccessPRIVATE && access != models.BucketAccessPUBLIC && access != models.BucketAccessCUSTOM {
   573  		return fmt.Errorf("access: `%s` not supported", access)
   574  	}
   575  
   576  	bucketAccessPolicy := policy.BucketAccessPolicy{Version: minioIAMPolicy.DefaultVersion}
   577  	if access == models.BucketAccessCUSTOM {
   578  		err := client.setBucketPolicyWithContext(ctx, bucketName, policyDefinition)
   579  		if err != nil {
   580  			return err
   581  		}
   582  		return nil
   583  	}
   584  	bucketPolicy := consoleAccess2policyAccess(access)
   585  	bucketAccessPolicy.Statements = policy.SetPolicy(bucketAccessPolicy.Statements,
   586  		bucketPolicy, bucketName, "")
   587  	policyJSON, err := json.Marshal(bucketAccessPolicy)
   588  	if err != nil {
   589  		return err
   590  	}
   591  	return client.setBucketPolicyWithContext(ctx, bucketName, string(policyJSON))
   592  }
   593  
   594  // getBucketSetPolicyResponse calls setBucketAccessPolicy() to set a access policy to a bucket
   595  // and returns the serialized output.
   596  func getBucketSetPolicyResponse(session *models.Principal, params bucketApi.BucketSetPolicyParams) (*models.Bucket, *CodedAPIError) {
   597  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   598  	defer cancel()
   599  
   600  	// get updated bucket details and return it
   601  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   602  	if err != nil {
   603  		return nil, ErrorWithContext(ctx, err)
   604  	}
   605  	// create a minioClient interface implementation
   606  	// defining the client to be used
   607  	minioClient := minioClient{client: mClient}
   608  
   609  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   610  	if err != nil {
   611  		return nil, ErrorWithContext(ctx, err)
   612  	}
   613  	// create a minioClient interface implementation
   614  	// defining the client to be used
   615  	adminClient := AdminClient{Client: mAdmin}
   616  	bucketName := params.Name
   617  	req := params.Body
   618  	if err := setBucketAccessPolicy(ctx, minioClient, bucketName, *req.Access, req.Definition); err != nil {
   619  		return nil, ErrorWithContext(ctx, err)
   620  	}
   621  	// set bucket access policy
   622  	bucket, err := getBucketInfo(ctx, minioClient, adminClient, bucketName)
   623  	if err != nil {
   624  		return nil, ErrorWithContext(ctx, err)
   625  	}
   626  	return bucket, nil
   627  }
   628  
   629  // putBucketTags sets tags for a bucket
   630  func getPutBucketTagsResponse(session *models.Principal, params bucketApi.PutBucketTagsParams) *CodedAPIError {
   631  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   632  	defer cancel()
   633  
   634  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   635  	if err != nil {
   636  		return ErrorWithContext(ctx, err)
   637  	}
   638  	// create a minioClient interface implementation
   639  	// defining the client to be used
   640  	minioClient := minioClient{client: mClient}
   641  
   642  	req := params.Body
   643  	bucketName := params.BucketName
   644  
   645  	newTagSet, err := tags.NewTags(req.Tags, true)
   646  	if err != nil {
   647  		return ErrorWithContext(ctx, err)
   648  	}
   649  
   650  	err = minioClient.SetBucketTagging(ctx, bucketName, newTagSet)
   651  	if err != nil {
   652  		return ErrorWithContext(ctx, err)
   653  	}
   654  	return nil
   655  }
   656  
   657  // removeBucket deletes a bucket
   658  func removeBucket(client MinioClient, bucketName string) error {
   659  	return client.removeBucket(context.Background(), bucketName)
   660  }
   661  
   662  // getDeleteBucketResponse performs removeBucket() to delete a bucket
   663  func getDeleteBucketResponse(session *models.Principal, params bucketApi.DeleteBucketParams) *CodedAPIError {
   664  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   665  	defer cancel()
   666  	if params.Name == "" {
   667  		return ErrorWithContext(ctx, ErrBucketNameNotInRequest)
   668  	}
   669  	bucketName := params.Name
   670  
   671  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   672  	if err != nil {
   673  		return ErrorWithContext(ctx, err)
   674  	}
   675  	// create a minioClient interface implementation
   676  	// defining the client to be used
   677  	minioClient := minioClient{client: mClient}
   678  	if err := removeBucket(minioClient, bucketName); err != nil {
   679  		resp := ErrorWithContext(ctx, err)
   680  		errResp := minio.ToErrorResponse(err)
   681  		if errResp.Code == "NoSuchBucket" {
   682  			resp.Code = 404
   683  		}
   684  		return resp
   685  	}
   686  	return nil
   687  }
   688  
   689  // getBucketInfo return bucket information including name, policy access, size and creation date
   690  func getBucketInfo(ctx context.Context, client MinioClient, adminClient MinioAdmin, bucketName string) (*models.Bucket, error) {
   691  	var bucketAccess models.BucketAccess
   692  	policyStr, err := client.getBucketPolicy(context.Background(), bucketName)
   693  	if err != nil {
   694  		// we can tolerate this errors
   695  		ErrorWithContext(ctx, fmt.Errorf("error getting bucket policy: %v", err))
   696  	}
   697  
   698  	if policyStr == "" {
   699  		bucketAccess = models.BucketAccessPRIVATE
   700  	} else {
   701  		var p policy.BucketAccessPolicy
   702  		if err = json.Unmarshal([]byte(policyStr), &p); err != nil {
   703  			return nil, err
   704  		}
   705  		policyAccess := policy.GetPolicy(p.Statements, bucketName, "")
   706  		if len(p.Statements) > 0 && policyAccess == policy.BucketPolicyNone {
   707  			bucketAccess = models.BucketAccessCUSTOM
   708  		} else {
   709  			bucketAccess = policyAccess2consoleAccess(policyAccess)
   710  		}
   711  	}
   712  	bucketTags, err := client.GetBucketTagging(ctx, bucketName)
   713  	if err != nil {
   714  		// we can tolerate this errors
   715  		ErrorWithContext(ctx, fmt.Errorf("error getting bucket tags: %v", err))
   716  	}
   717  	bucketDetails := &models.BucketDetails{}
   718  	if bucketTags != nil {
   719  		bucketDetails.Tags = bucketTags.ToMap()
   720  	}
   721  
   722  	info, err := adminClient.AccountInfo(ctx)
   723  	if err != nil {
   724  		return nil, err
   725  	}
   726  
   727  	var bucketInfo madmin.BucketAccessInfo
   728  
   729  	for _, bucket := range info.Buckets {
   730  		if bucket.Name == bucketName {
   731  			bucketInfo = bucket
   732  		}
   733  	}
   734  
   735  	return &models.Bucket{
   736  		Name:         &bucketName,
   737  		Access:       &bucketAccess,
   738  		Definition:   policyStr,
   739  		CreationDate: bucketInfo.Created.Format(time.RFC3339),
   740  		Size:         int64(bucketInfo.Size),
   741  		Details:      bucketDetails,
   742  		Objects:      int64(bucketInfo.Objects),
   743  	}, nil
   744  }
   745  
   746  // getBucketInfoResponse calls getBucketInfo() to get the bucket's info
   747  func getBucketInfoResponse(session *models.Principal, params bucketApi.BucketInfoParams) (*models.Bucket, *CodedAPIError) {
   748  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   749  	defer cancel()
   750  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   751  	if err != nil {
   752  		return nil, ErrorWithContext(ctx, err)
   753  	}
   754  	// create a minioClient interface implementation
   755  	// defining the client to be used
   756  	minioClient := minioClient{client: mClient}
   757  
   758  	mAdmin, err := NewMinioAdminClient(params.HTTPRequest.Context(), session)
   759  	if err != nil {
   760  		return nil, ErrorWithContext(ctx, err)
   761  	}
   762  	// create a minioClient interface implementation
   763  	// defining the client to be used
   764  	adminClient := AdminClient{Client: mAdmin}
   765  
   766  	bucket, err := getBucketInfo(ctx, minioClient, adminClient, params.Name)
   767  	if err != nil {
   768  		return nil, ErrorWithContext(ctx, err)
   769  	}
   770  	return bucket, nil
   771  }
   772  
   773  // policyAccess2consoleAccess gets the equivalent of policy.BucketPolicy to models.BucketAccess
   774  func policyAccess2consoleAccess(bucketPolicy policy.BucketPolicy) (bucketAccess models.BucketAccess) {
   775  	switch bucketPolicy {
   776  	case policy.BucketPolicyReadWrite:
   777  		bucketAccess = models.BucketAccessPUBLIC
   778  	case policy.BucketPolicyNone:
   779  		bucketAccess = models.BucketAccessPRIVATE
   780  	default:
   781  		bucketAccess = models.BucketAccessCUSTOM
   782  	}
   783  	return bucketAccess
   784  }
   785  
   786  // consoleAccess2policyAccess gets the equivalent of models.BucketAccess to policy.BucketPolicy
   787  func consoleAccess2policyAccess(bucketAccess models.BucketAccess) (bucketPolicy policy.BucketPolicy) {
   788  	switch bucketAccess {
   789  	case models.BucketAccessPUBLIC:
   790  		bucketPolicy = policy.BucketPolicyReadWrite
   791  	case models.BucketAccessPRIVATE:
   792  		bucketPolicy = policy.BucketPolicyNone
   793  	}
   794  	return bucketPolicy
   795  }
   796  
   797  // enableBucketEncryption will enable bucket encryption based on two encryption algorithms, sse-s3 (server side encryption with external KMS) or sse-kms (aws s3 kms key)
   798  func enableBucketEncryption(ctx context.Context, client MinioClient, bucketName string, encryptionType models.BucketEncryptionType, kmsKeyID string) error {
   799  	var config *sse.Configuration
   800  	switch encryptionType {
   801  	case models.BucketEncryptionTypeSseDashKms:
   802  		config = sse.NewConfigurationSSEKMS(kmsKeyID)
   803  	case models.BucketEncryptionTypeSseDashS3:
   804  		config = sse.NewConfigurationSSES3()
   805  	default:
   806  		return ErrInvalidEncryptionAlgorithm
   807  	}
   808  	return client.setBucketEncryption(ctx, bucketName, config)
   809  }
   810  
   811  // enableBucketEncryptionResponse calls enableBucketEncryption() to create new encryption configuration for provided bucket name
   812  func enableBucketEncryptionResponse(session *models.Principal, params bucketApi.EnableBucketEncryptionParams) *CodedAPIError {
   813  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   814  	defer cancel()
   815  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   816  	if err != nil {
   817  		return ErrorWithContext(ctx, err)
   818  	}
   819  	// create a minioClient interface implementation
   820  	// defining the client to be used
   821  	minioClient := minioClient{client: mClient}
   822  	if err := enableBucketEncryption(ctx, minioClient, params.BucketName, *params.Body.EncType, params.Body.KmsKeyID); err != nil {
   823  		return ErrorWithContext(ctx, err)
   824  	}
   825  	return nil
   826  }
   827  
   828  // disableBucketEncryption will disable bucket for the provided bucket name
   829  func disableBucketEncryption(ctx context.Context, client MinioClient, bucketName string) error {
   830  	return client.removeBucketEncryption(ctx, bucketName)
   831  }
   832  
   833  // disableBucketEncryptionResponse calls disableBucketEncryption()
   834  func disableBucketEncryptionResponse(session *models.Principal, params bucketApi.DisableBucketEncryptionParams) *CodedAPIError {
   835  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   836  	defer cancel()
   837  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   838  	if err != nil {
   839  		return ErrorWithContext(ctx, err)
   840  	}
   841  	// create a minioClient interface implementation
   842  	// defining the client to be used
   843  	minioClient := minioClient{client: mClient}
   844  	if err := disableBucketEncryption(ctx, minioClient, params.BucketName); err != nil {
   845  		return ErrorWithContext(ctx, err)
   846  	}
   847  	return nil
   848  }
   849  
   850  func getBucketEncryptionInfo(ctx context.Context, client MinioClient, bucketName string) (*models.BucketEncryptionInfo, error) {
   851  	bucketInfo, err := client.getBucketEncryption(ctx, bucketName)
   852  	if err != nil {
   853  		return nil, err
   854  	}
   855  	if len(bucketInfo.Rules) == 0 {
   856  		return nil, ErrDefault
   857  	}
   858  	return &models.BucketEncryptionInfo{Algorithm: bucketInfo.Rules[0].Apply.SSEAlgorithm, KmsMasterKeyID: bucketInfo.Rules[0].Apply.KmsMasterKeyID}, nil
   859  }
   860  
   861  func getBucketEncryptionInfoResponse(session *models.Principal, params bucketApi.GetBucketEncryptionInfoParams) (*models.BucketEncryptionInfo, *CodedAPIError) {
   862  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   863  	defer cancel()
   864  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   865  	if err != nil {
   866  		return nil, ErrorWithContext(ctx, err)
   867  	}
   868  	// create a minioClient interface implementation
   869  	// defining the client to be used
   870  	minioClient := minioClient{client: mClient}
   871  	bucketInfo, err := getBucketEncryptionInfo(ctx, minioClient, params.BucketName)
   872  	if err != nil {
   873  		return nil, ErrorWithContext(ctx, ErrSSENotConfigured, err)
   874  	}
   875  	return bucketInfo, nil
   876  }
   877  
   878  // setBucketRetentionConfig sets object lock configuration on a bucket
   879  func setBucketRetentionConfig(ctx context.Context, client MinioClient, bucketName string, mode models.ObjectRetentionMode, unit models.ObjectRetentionUnit, validity *int32) error {
   880  	if validity == nil {
   881  		return errors.New("retention validity can't be nil")
   882  	}
   883  
   884  	var retentionMode minio.RetentionMode
   885  	switch mode {
   886  	case models.ObjectRetentionModeGovernance:
   887  		retentionMode = minio.Governance
   888  	case models.ObjectRetentionModeCompliance:
   889  		retentionMode = minio.Compliance
   890  	default:
   891  		return errors.New("invalid retention mode")
   892  	}
   893  
   894  	var retentionUnit minio.ValidityUnit
   895  	switch unit {
   896  	case models.ObjectRetentionUnitDays:
   897  		retentionUnit = minio.Days
   898  	case models.ObjectRetentionUnitYears:
   899  		retentionUnit = minio.Years
   900  	default:
   901  		return errors.New("invalid retention unit")
   902  	}
   903  
   904  	retentionValidity := uint(*validity)
   905  	return client.setObjectLockConfig(ctx, bucketName, &retentionMode, &retentionValidity, &retentionUnit)
   906  }
   907  
   908  func getSetBucketRetentionConfigResponse(session *models.Principal, params bucketApi.SetBucketRetentionConfigParams) *CodedAPIError {
   909  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   910  	defer cancel()
   911  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   912  	if err != nil {
   913  		return ErrorWithContext(ctx, err)
   914  	}
   915  	// create a minioClient interface implementation
   916  	// defining the client to be used
   917  	minioClient := minioClient{client: mClient}
   918  	err = setBucketRetentionConfig(ctx, minioClient, params.BucketName, *params.Body.Mode, *params.Body.Unit, params.Body.Validity)
   919  	if err != nil {
   920  		return ErrorWithContext(ctx, err)
   921  	}
   922  	return nil
   923  }
   924  
   925  func getBucketRetentionConfig(ctx context.Context, client MinioClient, bucketName string) (*models.GetBucketRetentionConfig, error) {
   926  	m, v, u, err := client.getBucketObjectLockConfig(ctx, bucketName)
   927  	if err != nil {
   928  		errResp := minio.ToErrorResponse(probe.NewError(err).ToGoError())
   929  		if errResp.Code == "ObjectLockConfigurationNotFoundError" {
   930  			return &models.GetBucketRetentionConfig{}, nil
   931  		}
   932  		return nil, err
   933  	}
   934  
   935  	// These values can be empty when all are empty, it means
   936  	// object was created with object locking enabled but
   937  	// does not have any default object locking configuration.
   938  	if m == nil && v == nil && u == nil {
   939  		return &models.GetBucketRetentionConfig{}, nil
   940  	}
   941  
   942  	var mode models.ObjectRetentionMode
   943  	var unit models.ObjectRetentionUnit
   944  
   945  	if m != nil {
   946  		switch *m {
   947  		case minio.Governance:
   948  			mode = models.ObjectRetentionModeGovernance
   949  		case minio.Compliance:
   950  			mode = models.ObjectRetentionModeCompliance
   951  		default:
   952  			return nil, errors.New("invalid retention mode")
   953  		}
   954  	}
   955  
   956  	if u != nil {
   957  		switch *u {
   958  		case minio.Days:
   959  			unit = models.ObjectRetentionUnitDays
   960  		case minio.Years:
   961  			unit = models.ObjectRetentionUnitYears
   962  		default:
   963  			return nil, errors.New("invalid retention unit")
   964  		}
   965  	}
   966  
   967  	var validity int32
   968  	if v != nil {
   969  		validity = int32(*v)
   970  	}
   971  
   972  	config := &models.GetBucketRetentionConfig{
   973  		Mode:     mode,
   974  		Unit:     unit,
   975  		Validity: validity,
   976  	}
   977  	return config, nil
   978  }
   979  
   980  func getBucketRetentionConfigResponse(session *models.Principal, params bucketApi.GetBucketRetentionConfigParams) (*models.GetBucketRetentionConfig, *CodedAPIError) {
   981  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
   982  	defer cancel()
   983  	bucketName := params.BucketName
   984  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
   985  	if err != nil {
   986  		return nil, ErrorWithContext(ctx, err)
   987  	}
   988  
   989  	// create a minioClient interface implementation
   990  	// defining the client to be used
   991  	minioClient := minioClient{client: mClient}
   992  
   993  	config, err := getBucketRetentionConfig(ctx, minioClient, bucketName)
   994  	if err != nil {
   995  		return nil, ErrorWithContext(ctx, err)
   996  	}
   997  	return config, nil
   998  }
   999  
  1000  func getBucketObjectLockingResponse(session *models.Principal, params bucketApi.GetBucketObjectLockingStatusParams) (*models.BucketObLockingResponse, *CodedAPIError) {
  1001  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
  1002  	defer cancel()
  1003  	bucketName := params.BucketName
  1004  	mClient, err := newMinioClient(session, getClientIP(params.HTTPRequest))
  1005  	if err != nil {
  1006  		return nil, ErrorWithContext(ctx, fmt.Errorf("error creating MinIO Client: %v", err))
  1007  	}
  1008  	// create a minioClient interface implementation
  1009  	// defining the client to be used
  1010  	minioClient := minioClient{client: mClient}
  1011  
  1012  	// we will tolerate this call failing
  1013  	_, _, _, _, err = minioClient.getObjectLockConfig(ctx, bucketName)
  1014  	if err != nil {
  1015  		if minio.ToErrorResponse(err).Code == "ObjectLockConfigurationNotFoundError" {
  1016  			return &models.BucketObLockingResponse{
  1017  				ObjectLockingEnabled: false,
  1018  			}, nil
  1019  		}
  1020  		return nil, ErrorWithContext(ctx, err)
  1021  	}
  1022  
  1023  	// serialize output
  1024  	return &models.BucketObLockingResponse{
  1025  		ObjectLockingEnabled: true,
  1026  	}, nil
  1027  }
  1028  
  1029  func getBucketRewindResponse(session *models.Principal, params bucketApi.GetBucketRewindParams) (*models.RewindResponse, *CodedAPIError) {
  1030  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
  1031  	defer cancel()
  1032  	prefix := ""
  1033  	if params.Prefix != nil {
  1034  		encodedPrefix := SanitizeEncodedPrefix(*params.Prefix)
  1035  		decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix)
  1036  		if err != nil {
  1037  			return nil, ErrorWithContext(ctx, err)
  1038  		}
  1039  		prefix = string(decodedPrefix)
  1040  	}
  1041  	s3Client, err := newS3BucketClient(session, params.BucketName, prefix, getClientIP(params.HTTPRequest))
  1042  	if err != nil {
  1043  		return nil, ErrorWithContext(ctx, fmt.Errorf("error creating S3Client: %v", err))
  1044  	}
  1045  
  1046  	// create a mc S3Client interface implementation
  1047  	// defining the client to be used
  1048  	mcClient := mcClient{client: s3Client}
  1049  
  1050  	parsedDate, errDate := time.Parse(time.RFC3339, params.Date)
  1051  
  1052  	if errDate != nil {
  1053  		return nil, ErrorWithContext(ctx, errDate)
  1054  	}
  1055  
  1056  	var rewindItems []*models.RewindItem
  1057  
  1058  	for content := range mcClient.client.List(ctx, cmd.ListOptions{TimeRef: parsedDate, WithDeleteMarkers: true}) {
  1059  		// build object name
  1060  		name := strings.ReplaceAll(content.URL.Path, fmt.Sprintf("/%s/", params.BucketName), "")
  1061  
  1062  		listElement := &models.RewindItem{
  1063  			LastModified: content.Time.Format(time.RFC3339),
  1064  			Size:         content.Size,
  1065  			VersionID:    content.VersionID,
  1066  			DeleteFlag:   content.IsDeleteMarker,
  1067  			Action:       "",
  1068  			Name:         name,
  1069  		}
  1070  
  1071  		rewindItems = append(rewindItems, listElement)
  1072  	}
  1073  
  1074  	return &models.RewindResponse{
  1075  		Objects: rewindItems,
  1076  	}, nil
  1077  }
  1078  
  1079  func getMaxShareLinkExpirationResponse(session *models.Principal, params bucketApi.GetMaxShareLinkExpParams) (*models.MaxShareLinkExpResponse, *CodedAPIError) {
  1080  	ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
  1081  	defer cancel()
  1082  
  1083  	maxShareLinkExpSeconds, err := getMaxShareLinkExpirationSeconds(session)
  1084  	if err != nil {
  1085  		return nil, ErrorWithContext(ctx, err)
  1086  	}
  1087  	return &models.MaxShareLinkExpResponse{Exp: swag.Int64(maxShareLinkExpSeconds)}, nil
  1088  }
  1089  
  1090  // getMaxShareLinkExpirationSeconds returns the max share link expiration time in seconds which is the sts token expiration time
  1091  func getMaxShareLinkExpirationSeconds(session *models.Principal) (int64, error) {
  1092  	creds := getConsoleCredentialsFromSession(session)
  1093  
  1094  	val, err := creds.Get()
  1095  	if err != nil {
  1096  		return 0, err
  1097  	}
  1098  
  1099  	if val.SignerType.IsAnonymous() {
  1100  		return 0, ErrAccessDenied
  1101  	}
  1102  	maxShareLinkExp := token.GetConsoleSTSDuration()
  1103  
  1104  	return int64(maxShareLinkExp.Seconds()), nil
  1105  }