2020-04-02 12:51:51 -07:00
// This file is part of MinIO Console Server
2021-01-19 17:04:13 -06:00
// Copyright (c) 2021 MinIO, Inc.
2020-04-01 18:18:57 -07:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2023-12-26 15:07:30 -06:00
package api
2020-04-01 18:18:57 -07:00
import (
"context"
"encoding/json"
2022-05-05 13:44:10 -07:00
"errors"
2020-04-01 18:18:57 -07:00
"fmt"
2024-12-30 23:59:10 +05:30
"net/http"
2020-04-01 18:18:57 -07:00
"strings"
"time"
2022-04-11 16:20:30 -07:00
"github.com/minio/minio-go/v7"
2023-08-16 14:18:08 -07:00
"github.com/minio/madmin-go/v3"
2021-06-23 01:10:54 -05:00
"github.com/minio/mc/cmd"
2020-12-15 19:25:43 -06:00
"github.com/minio/mc/pkg/probe"
2024-12-30 23:59:10 +05:30
"github.com/minio/minio-go/v7/pkg/credentials"
2020-10-25 12:56:23 -07:00
"github.com/minio/minio-go/v7/pkg/sse"
2021-11-11 18:36:18 -08:00
"github.com/minio/minio-go/v7/pkg/tags"
2020-09-28 12:46:08 -05:00
2020-04-01 18:18:57 -07:00
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
2023-12-26 15:07:30 -06:00
"github.com/minio/console/api/operations"
bucketApi "github.com/minio/console/api/operations/bucket"
2020-07-26 00:34:17 -07:00
"github.com/minio/console/models"
2023-10-19 14:03:14 -07:00
"github.com/minio/console/pkg/auth/token"
2020-07-25 14:38:16 -07:00
"github.com/minio/minio-go/v7/pkg/policy"
2024-05-24 10:44:55 -07:00
minioIAMPolicy "github.com/minio/pkg/v3/policy"
2020-04-01 18:18:57 -07:00
)
2020-07-26 00:34:17 -07:00
func registerBucketsHandlers ( api * operations . ConsoleAPI ) {
2020-04-01 18:18:57 -07:00
// list buckets
2022-04-27 11:45:04 -07:00
api . BucketListBucketsHandler = bucketApi . ListBucketsHandlerFunc ( func ( params bucketApi . ListBucketsParams , session * models . Principal ) middleware . Responder {
2022-04-28 12:55:06 -07:00
listBucketsResponse , err := getListBucketsResponse ( session , params )
2020-04-01 18:18:57 -07:00
if err != nil {
2023-08-16 14:18:08 -07:00
return bucketApi . NewListBucketsDefault ( err . Code ) . WithPayload ( err . APIError )
2020-04-01 18:18:57 -07:00
}
2022-04-27 11:45:04 -07:00
return bucketApi . NewListBucketsOK ( ) . WithPayload ( listBucketsResponse )
2020-04-01 18:18:57 -07:00
} )
// make bucket
2022-04-27 11:45:04 -07:00
api . BucketMakeBucketHandler = bucketApi . MakeBucketHandlerFunc ( func ( params bucketApi . MakeBucketParams , session * models . Principal ) middleware . Responder {
2023-03-17 17:36:42 -06:00
makeBucketResponse , err := getMakeBucketResponse ( session , params )
if err != nil {
2023-08-16 14:18:08 -07:00
return bucketApi . NewMakeBucketDefault ( err . Code ) . WithPayload ( err . APIError )
2020-04-01 18:18:57 -07:00
}
2023-03-17 17:36:42 -06:00
return bucketApi . NewMakeBucketOK ( ) . WithPayload ( makeBucketResponse )
2020-04-01 18:18:57 -07:00
} )
// get bucket info
2022-04-27 11:45:04 -07:00
api . BucketBucketInfoHandler = bucketApi . BucketInfoHandlerFunc ( func ( params bucketApi . BucketInfoParams , session * models . Principal ) middleware . Responder {
2020-07-10 19:14:28 -07:00
bucketInfoResp , err := getBucketInfoResponse ( session , params )
2020-04-01 18:18:57 -07:00
if err != nil {
2023-08-16 14:18:08 -07:00
return bucketApi . NewBucketInfoDefault ( err . Code ) . WithPayload ( err . APIError )
2020-04-01 18:18:57 -07:00
}
2022-04-27 11:45:04 -07:00
return bucketApi . NewBucketInfoOK ( ) . WithPayload ( bucketInfoResp )
2020-04-01 18:18:57 -07:00
} )
2021-11-11 18:36:18 -08:00
// set bucket tags
2022-04-27 11:45:04 -07:00
api . BucketPutBucketTagsHandler = bucketApi . PutBucketTagsHandlerFunc ( func ( params bucketApi . PutBucketTagsParams , session * models . Principal ) middleware . Responder {
2022-04-28 12:55:06 -07:00
err := getPutBucketTagsResponse ( session , params )
2021-11-11 18:36:18 -08:00
if err != nil {
2023-08-16 14:18:08 -07:00
return bucketApi . NewPutBucketTagsDefault ( err . Code ) . WithPayload ( err . APIError )
2021-11-11 18:36:18 -08:00
}
2022-04-27 11:45:04 -07:00
return bucketApi . NewPutBucketTagsOK ( )
2021-11-11 18:36:18 -08:00
} )
2020-09-28 12:46:08 -05:00
// get bucket versioning
2022-04-27 11:45:04 -07:00
api . BucketGetBucketVersioningHandler = bucketApi . GetBucketVersioningHandlerFunc ( func ( params bucketApi . GetBucketVersioningParams , session * models . Principal ) middleware . Responder {
2022-04-28 12:55:06 -07:00
getBucketVersioning , err := getBucketVersionedResponse ( session , params )
2020-09-28 12:46:08 -05:00
if err != nil {
2023-08-16 14:18:08 -07:00
return bucketApi . NewGetBucketVersioningDefault ( err . Code ) . WithPayload ( err . APIError )
2020-09-28 12:46:08 -05:00
}
2022-04-27 11:45:04 -07:00
return bucketApi . NewGetBucketVersioningOK ( ) . WithPayload ( getBucketVersioning )
2020-09-28 12:46:08 -05:00
} )
2021-03-19 18:48:58 -06:00
// update bucket versioning
2022-04-27 11:45:04 -07:00
api . BucketSetBucketVersioningHandler = bucketApi . SetBucketVersioningHandlerFunc ( func ( params bucketApi . SetBucketVersioningParams , session * models . Principal ) middleware . Responder {
2022-04-28 12:55:06 -07:00
err := setBucketVersioningResponse ( session , params )
2021-03-19 18:48:58 -06:00
if err != nil {
2023-08-16 14:18:08 -07:00
return bucketApi . NewSetBucketVersioningDefault ( err . Code ) . WithPayload ( err . APIError )
2021-03-19 18:48:58 -06:00
}
2022-04-27 11:45:04 -07:00
return bucketApi . NewSetBucketVersioningCreated ( )
2021-03-19 18:48:58 -06:00
} )
2021-06-23 01:10:54 -05:00
// get objects rewind for a bucket
2022-04-27 11:45:04 -07:00
api . BucketGetBucketRewindHandler = bucketApi . GetBucketRewindHandlerFunc ( func ( params bucketApi . GetBucketRewindParams , session * models . Principal ) middleware . Responder {
2021-06-23 01:10:54 -05:00
getBucketRewind , err := getBucketRewindResponse ( session , params )
if err != nil {
2023-08-16 14:18:08 -07:00
return bucketApi . NewGetBucketRewindDefault ( err . Code ) . WithPayload ( err . APIError )
2021-06-23 01:10:54 -05:00
}
2022-04-27 11:45:04 -07:00
return bucketApi . NewGetBucketRewindOK ( ) . WithPayload ( getBucketRewind )
2021-06-23 01:10:54 -05:00
} )
2023-10-19 14:03:14 -07:00
// get max allowed share link expiration time
api . BucketGetMaxShareLinkExpHandler = bucketApi . GetMaxShareLinkExpHandlerFunc ( func ( params bucketApi . GetMaxShareLinkExpParams , session * models . Principal ) middleware . Responder {
val , err := getMaxShareLinkExpirationResponse ( session , params )
if err != nil {
return bucketApi . NewGetMaxShareLinkExpDefault ( err . Code ) . WithPayload ( err . APIError )
}
return bucketApi . NewGetMaxShareLinkExpOK ( ) . WithPayload ( val )
} )
2020-09-28 12:46:08 -05:00
}
2021-03-19 18:48:58 -06:00
type VersionState string
const (
VersionEnable VersionState = "enable"
2023-06-14 21:35:00 -06:00
VersionSuspend VersionState = "suspend"
2021-03-19 18:48:58 -06:00
)
// removeBucket deletes a bucket
2023-08-02 13:35:00 -06:00
func doSetVersioning ( ctx context . Context , client MCClient , state VersionState , excludePrefix [ ] string , excludeFolders bool ) error {
err := client . setVersioning ( ctx , string ( state ) , excludePrefix , excludeFolders )
2021-03-19 18:48:58 -06:00
if err != nil {
return err . Cause
}
return nil
}
2023-08-16 14:18:08 -07:00
func setBucketVersioningResponse ( session * models . Principal , params bucketApi . SetBucketVersioningParams ) * CodedAPIError {
2022-04-28 12:55:06 -07:00
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
defer cancel ( )
bucketName := params . BucketName
2023-06-14 12:36:48 -07:00
s3Client , err := newS3BucketClient ( session , bucketName , "" , getClientIP ( params . HTTPRequest ) )
2021-03-19 18:48:58 -06:00
if err != nil {
2022-04-28 12:55:06 -07:00
return ErrorWithContext ( ctx , err )
2021-03-19 18:48:58 -06:00
}
// create a mc S3Client interface implementation
// defining the client to be used
amcClient := mcClient { client : s3Client }
2023-06-14 21:35:00 -06:00
versioningState := VersionSuspend
2021-03-19 18:48:58 -06:00
2023-08-02 13:35:00 -06:00
if params . Body . Enabled {
2021-03-19 18:48:58 -06:00
versioningState = VersionEnable
}
2023-08-02 13:35:00 -06:00
var excludePrefixes [ ] string
if params . Body . ExcludePrefixes != nil {
excludePrefixes = params . Body . ExcludePrefixes
}
excludeFolders := params . Body . ExcludeFolders
if err := doSetVersioning ( ctx , amcClient , versioningState , excludePrefixes , excludeFolders ) ; err != nil {
2022-04-28 12:55:06 -07:00
return ErrorWithContext ( ctx , fmt . Errorf ( "error setting versioning for bucket: %s" , err ) )
2021-03-19 18:48:58 -06:00
}
return nil
}
2023-08-16 14:18:08 -07:00
func getBucketVersionedResponse ( session * models . Principal , params bucketApi . GetBucketVersioningParams ) ( * models . BucketVersioningResponse , * CodedAPIError ) {
2022-04-28 12:55:06 -07:00
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
2020-09-28 12:46:08 -05:00
defer cancel ( )
2023-06-14 12:36:48 -07:00
mClient , err := newMinioClient ( session , getClientIP ( params . HTTPRequest ) )
2020-09-28 12:46:08 -05:00
if err != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , err )
2020-09-28 12:46:08 -05:00
}
2021-07-19 12:24:35 -07:00
2020-09-28 12:46:08 -05:00
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient { client : mClient }
// we will tolerate this call failing
2022-04-28 12:55:06 -07:00
res , err := minioClient . getBucketVersioning ( ctx , params . BucketName )
2020-09-28 12:46:08 -05:00
if err != nil {
2022-04-28 12:55:06 -07:00
ErrorWithContext ( ctx , fmt . Errorf ( "error versioning bucket: %v" , err ) )
2020-09-28 12:46:08 -05:00
}
2023-03-03 00:11:44 +05:30
excludedPrefixes := make ( [ ] * models . BucketVersioningResponseExcludedPrefixesItems0 , len ( res . ExcludedPrefixes ) )
for i , v := range res . ExcludedPrefixes {
excludedPrefixes [ i ] = & models . BucketVersioningResponseExcludedPrefixesItems0 {
Prefix : v . Prefix ,
}
}
2020-09-28 12:46:08 -05:00
// serialize output
2021-07-19 12:24:35 -07:00
bucketVResponse := & models . BucketVersioningResponse {
2023-03-03 00:11:44 +05:30
ExcludeFolders : res . ExcludeFolders ,
ExcludedPrefixes : excludedPrefixes ,
MFADelete : res . MFADelete ,
Status : res . Status ,
2020-09-28 12:46:08 -05:00
}
2021-07-19 12:24:35 -07:00
return bucketVResponse , nil
}
2021-11-15 12:24:37 -08:00
// getAccountBuckets fetches a list of all buckets allowed to that particular client from MinIO Servers
2021-11-18 08:25:01 -08:00
func getAccountBuckets ( ctx context . Context , client MinioAdmin ) ( [ ] * models . Bucket , error ) {
2021-07-19 11:48:50 -07:00
info , err := client . AccountInfo ( ctx )
2020-04-01 18:18:57 -07:00
if err != nil {
return [ ] * models . Bucket { } , err
}
2023-06-08 13:06:49 -06:00
bucketInfos := [ ] * models . Bucket { }
2020-05-18 13:36:18 -07:00
for _ , bucket := range info . Buckets {
2021-07-19 12:24:35 -07:00
bucketElem := & models . Bucket {
CreationDate : bucket . Created . Format ( time . RFC3339 ) ,
2021-09-20 11:13:34 -07:00
Details : & models . BucketDetails {
Quota : nil ,
} ,
RwAccess : & models . BucketRwAccess {
Read : bucket . Access . Read ,
Write : bucket . Access . Write ,
} ,
Name : swag . String ( bucket . Name ) ,
Objects : int64 ( bucket . Objects ) ,
Size : int64 ( bucket . Size ) ,
}
if bucket . Details != nil {
if bucket . Details . Tagging != nil {
bucketElem . Details . Tags = bucket . Details . Tagging . ToMap ( )
}
bucketElem . Details . Locking = bucket . Details . Locking
bucketElem . Details . Replication = bucket . Details . Replication
bucketElem . Details . Versioning = bucket . Details . Versioning
bucketElem . Details . VersioningSuspended = bucket . Details . VersioningSuspended
if bucket . Details . Quota != nil {
bucketElem . Details . Quota = & models . BucketDetailsQuota {
Quota : int64 ( bucket . Details . Quota . Quota ) ,
Type : string ( bucket . Details . Quota . Type ) ,
}
}
2021-07-19 12:24:35 -07:00
}
2021-09-20 11:13:34 -07:00
2020-04-01 18:18:57 -07:00
bucketInfos = append ( bucketInfos , bucketElem )
}
return bucketInfos , nil
}
// getListBucketsResponse performs listBuckets() and serializes it to the handler's output
2023-08-16 14:18:08 -07:00
func getListBucketsResponse ( session * models . Principal , params bucketApi . ListBucketsParams ) ( * models . ListBucketsResponse , * CodedAPIError ) {
2022-04-28 12:55:06 -07:00
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
2020-04-01 18:18:57 -07:00
defer cancel ( )
2020-05-18 13:36:18 -07:00
2023-06-14 12:36:48 -07:00
mAdmin , err := NewMinioAdminClient ( params . HTTPRequest . Context ( ) , session )
2020-04-01 18:18:57 -07:00
if err != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , err )
2020-04-01 18:18:57 -07:00
}
// create a minioClient interface implementation
// defining the client to be used
2021-07-19 11:48:50 -07:00
adminClient := AdminClient { Client : mAdmin }
2021-11-18 08:25:01 -08:00
buckets , err := getAccountBuckets ( ctx , adminClient )
2020-04-01 18:18:57 -07:00
if err != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , err )
2020-04-01 18:18:57 -07:00
}
2020-05-18 13:36:18 -07:00
2020-04-01 18:18:57 -07:00
// serialize output
listBucketsResponse := & models . ListBucketsResponse {
Buckets : buckets ,
Total : int64 ( len ( buckets ) ) ,
}
return listBucketsResponse , nil
}
// makeBucket creates a bucket for an specific minio client
2020-11-25 12:40:39 -06:00
func makeBucket ( ctx context . Context , client MinioClient , bucketName string , objectLocking bool ) error {
2020-04-01 18:18:57 -07:00
// creates a new bucket with bucketName with a context to control cancellations and timeouts.
2021-06-07 20:53:03 -07:00
return client . makeBucketWithContext ( ctx , bucketName , "" , objectLocking )
2020-04-06 09:59:19 -07:00
}
// getMakeBucketResponse performs makeBucket() to create a bucket with its access policy
2023-08-16 14:18:08 -07:00
func getMakeBucketResponse ( session * models . Principal , params bucketApi . MakeBucketParams ) ( * models . MakeBucketsResponse , * CodedAPIError ) {
2022-04-28 12:55:06 -07:00
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
2020-04-06 09:59:19 -07:00
defer cancel ( )
// bucket request needed to proceed
2022-04-28 12:55:06 -07:00
br := params . Body
2020-04-06 09:59:19 -07:00
if br == nil {
2023-03-17 17:36:42 -06:00
return nil , ErrorWithContext ( ctx , ErrBucketBodyNotInRequest )
2020-04-06 09:59:19 -07:00
}
2023-06-14 12:36:48 -07:00
mClient , err := newMinioClient ( session , getClientIP ( params . HTTPRequest ) )
2020-04-06 09:59:19 -07:00
if err != nil {
2023-03-17 17:36:42 -06:00
return nil , ErrorWithContext ( ctx , err )
2020-04-06 09:59:19 -07:00
}
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient { client : mClient }
2025-03-11 03:30:53 -06:00
if err := makeBucket ( ctx , minioClient , * br . Name , false ) ; err != nil {
2023-03-17 17:36:42 -06:00
return nil , ErrorWithContext ( ctx , err )
2020-04-01 18:18:57 -07:00
}
2020-11-25 12:40:39 -06:00
2022-04-28 12:55:06 -07:00
// make sure to delete bucket if an errors occurs after bucket was created
2020-12-11 10:22:25 -06:00
defer func ( ) {
if err != nil {
2022-04-28 12:55:06 -07:00
ErrorWithContext ( ctx , fmt . Errorf ( "error creating bucket: %v" , err ) )
2020-12-11 10:22:25 -06:00
if err := removeBucket ( minioClient , * br . Name ) ; err != nil {
2022-04-28 12:55:06 -07:00
ErrorWithContext ( ctx , fmt . Errorf ( "error removing bucket: %v" , err ) )
2020-12-11 10:22:25 -06:00
}
}
} ( )
2023-03-17 17:36:42 -06:00
return & models . MakeBucketsResponse { BucketName : * br . Name } , nil
2020-04-01 18:18:57 -07:00
}
// setBucketAccessPolicy set the access permissions on an existing bucket.
2021-12-28 18:21:29 -08:00
func setBucketAccessPolicy ( ctx context . Context , client MinioClient , bucketName string , access models . BucketAccess , policyDefinition string ) error {
2020-04-01 18:18:57 -07:00
if strings . TrimSpace ( bucketName ) == "" {
return fmt . Errorf ( "error: bucket name not present" )
}
if strings . TrimSpace ( string ( access ) ) == "" {
return fmt . Errorf ( "error: bucket access not present" )
}
// Prepare policyJSON corresponding to the access type
2021-12-28 18:21:29 -08:00
if access != models . BucketAccessPRIVATE && access != models . BucketAccessPUBLIC && access != models . BucketAccessCUSTOM {
2020-04-01 18:18:57 -07:00
return fmt . Errorf ( "access: `%s` not supported" , access )
}
bucketAccessPolicy := policy . BucketAccessPolicy { Version : minioIAMPolicy . DefaultVersion }
2021-12-28 18:21:29 -08:00
if access == models . BucketAccessCUSTOM {
err := client . setBucketPolicyWithContext ( ctx , bucketName , policyDefinition )
if err != nil {
return err
}
return nil
}
bucketPolicy := consoleAccess2policyAccess ( access )
2020-04-01 18:18:57 -07:00
bucketAccessPolicy . Statements = policy . SetPolicy ( bucketAccessPolicy . Statements ,
2021-11-15 17:48:25 -08:00
bucketPolicy , bucketName , "" )
2020-04-01 18:18:57 -07:00
policyJSON , err := json . Marshal ( bucketAccessPolicy )
if err != nil {
return err
}
return client . setBucketPolicyWithContext ( ctx , bucketName , string ( policyJSON ) )
}
2021-11-11 18:36:18 -08:00
// putBucketTags sets tags for a bucket
2023-08-16 14:18:08 -07:00
func getPutBucketTagsResponse ( session * models . Principal , params bucketApi . PutBucketTagsParams ) * CodedAPIError {
2022-04-28 12:55:06 -07:00
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
2021-11-11 18:36:18 -08:00
defer cancel ( )
2023-06-14 12:36:48 -07:00
mClient , err := newMinioClient ( session , getClientIP ( params . HTTPRequest ) )
2021-11-11 18:36:18 -08:00
if err != nil {
2022-04-28 12:55:06 -07:00
return ErrorWithContext ( ctx , err )
2021-11-11 18:36:18 -08:00
}
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient { client : mClient }
2022-04-28 12:55:06 -07:00
req := params . Body
bucketName := params . BucketName
2021-11-11 18:36:18 -08:00
newTagSet , err := tags . NewTags ( req . Tags , true )
if err != nil {
2022-04-28 12:55:06 -07:00
return ErrorWithContext ( ctx , err )
2021-11-11 18:36:18 -08:00
}
err = minioClient . SetBucketTagging ( ctx , bucketName , newTagSet )
if err != nil {
2022-04-28 12:55:06 -07:00
return ErrorWithContext ( ctx , err )
2021-11-11 18:36:18 -08:00
}
return nil
}
2020-04-01 18:18:57 -07:00
// removeBucket deletes a bucket
func removeBucket ( client MinioClient , bucketName string ) error {
2020-07-25 14:38:16 -07:00
return client . removeBucket ( context . Background ( ) , bucketName )
2020-04-01 18:18:57 -07:00
}
// getBucketInfo return bucket information including name, policy access, size and creation date
2022-02-01 21:48:58 -07:00
func getBucketInfo ( ctx context . Context , client MinioClient , adminClient MinioAdmin , bucketName string ) ( * models . Bucket , error ) {
2021-11-02 17:34:39 -07:00
var bucketAccess models . BucketAccess
policyStr , err := client . getBucketPolicy ( context . Background ( ) , bucketName )
if err != nil {
2022-04-28 12:55:06 -07:00
// we can tolerate this errors
ErrorWithContext ( ctx , fmt . Errorf ( "error getting bucket policy: %v" , err ) )
2021-11-02 17:34:39 -07:00
}
2020-04-01 18:18:57 -07:00
if policyStr == "" {
2021-12-28 18:21:29 -08:00
bucketAccess = models . BucketAccessPRIVATE
2020-04-01 18:18:57 -07:00
} else {
var p policy . BucketAccessPolicy
if err = json . Unmarshal ( [ ] byte ( policyStr ) , & p ) ; err != nil {
return nil , err
}
2021-12-28 18:21:29 -08:00
policyAccess := policy . GetPolicy ( p . Statements , bucketName , "" )
if len ( p . Statements ) > 0 && policyAccess == policy . BucketPolicyNone {
bucketAccess = models . BucketAccessCUSTOM
} else {
bucketAccess = policyAccess2consoleAccess ( policyAccess )
}
2020-04-01 18:18:57 -07:00
}
2021-11-11 18:36:18 -08:00
bucketTags , err := client . GetBucketTagging ( ctx , bucketName )
2021-11-18 08:25:01 -08:00
if err != nil {
2022-04-28 12:55:06 -07:00
// we can tolerate this errors
ErrorWithContext ( ctx , fmt . Errorf ( "error getting bucket tags: %v" , err ) )
2021-11-18 08:25:01 -08:00
}
bucketDetails := & models . BucketDetails { }
if bucketTags != nil {
bucketDetails . Tags = bucketTags . ToMap ( )
}
2022-02-01 21:48:58 -07:00
info , err := adminClient . AccountInfo ( ctx )
if err != nil {
return nil , err
}
var bucketInfo madmin . BucketAccessInfo
for _ , bucket := range info . Buckets {
if bucket . Name == bucketName {
bucketInfo = bucket
2024-05-29 16:50:23 -06:00
break
2022-02-01 21:48:58 -07:00
}
}
2021-11-18 08:25:01 -08:00
return & models . Bucket {
Name : & bucketName ,
Access : & bucketAccess ,
2021-12-28 18:21:29 -08:00
Definition : policyStr ,
2022-02-01 21:48:58 -07:00
CreationDate : bucketInfo . Created . Format ( time . RFC3339 ) ,
Size : int64 ( bucketInfo . Size ) ,
2021-11-18 08:25:01 -08:00
Details : bucketDetails ,
2022-02-01 21:48:58 -07:00
Objects : int64 ( bucketInfo . Objects ) ,
2021-11-18 08:25:01 -08:00
} , nil
2020-04-01 18:18:57 -07:00
}
// getBucketInfoResponse calls getBucketInfo() to get the bucket's info
2023-08-16 14:18:08 -07:00
func getBucketInfoResponse ( session * models . Principal , params bucketApi . BucketInfoParams ) ( * models . Bucket , * CodedAPIError ) {
2022-04-28 12:55:06 -07:00
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
2021-11-02 17:34:39 -07:00
defer cancel ( )
2023-06-14 12:36:48 -07:00
mClient , err := newMinioClient ( session , getClientIP ( params . HTTPRequest ) )
2020-04-01 18:18:57 -07:00
if err != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , err )
2020-04-01 18:18:57 -07:00
}
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient { client : mClient }
2022-02-01 21:48:58 -07:00
2023-06-14 12:36:48 -07:00
mAdmin , err := NewMinioAdminClient ( params . HTTPRequest . Context ( ) , session )
2022-02-01 21:48:58 -07:00
if err != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , err )
2022-02-01 21:48:58 -07:00
}
// create a minioClient interface implementation
// defining the client to be used
adminClient := AdminClient { Client : mAdmin }
bucket , err := getBucketInfo ( ctx , minioClient , adminClient , params . Name )
2020-04-01 18:18:57 -07:00
if err != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , err )
2020-04-01 18:18:57 -07:00
}
return bucket , nil
}
2020-07-26 00:34:17 -07:00
// policyAccess2consoleAccess gets the equivalent of policy.BucketPolicy to models.BucketAccess
func policyAccess2consoleAccess ( bucketPolicy policy . BucketPolicy ) ( bucketAccess models . BucketAccess ) {
2020-04-01 18:18:57 -07:00
switch bucketPolicy {
case policy . BucketPolicyReadWrite :
bucketAccess = models . BucketAccessPUBLIC
case policy . BucketPolicyNone :
bucketAccess = models . BucketAccessPRIVATE
default :
bucketAccess = models . BucketAccessCUSTOM
}
return bucketAccess
}
2020-07-26 00:34:17 -07:00
// consoleAccess2policyAccess gets the equivalent of models.BucketAccess to policy.BucketPolicy
func consoleAccess2policyAccess ( bucketAccess models . BucketAccess ) ( bucketPolicy policy . BucketPolicy ) {
2020-04-01 18:18:57 -07:00
switch bucketAccess {
case models . BucketAccessPUBLIC :
bucketPolicy = policy . BucketPolicyReadWrite
case models . BucketAccessPRIVATE :
bucketPolicy = policy . BucketPolicyNone
}
return bucketPolicy
}
2020-10-25 12:56:23 -07:00
// 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)
func enableBucketEncryption ( ctx context . Context , client MinioClient , bucketName string , encryptionType models . BucketEncryptionType , kmsKeyID string ) error {
var config * sse . Configuration
switch encryptionType {
2021-06-08 12:35:39 -07:00
case models . BucketEncryptionTypeSseDashKms :
2020-10-25 12:56:23 -07:00
config = sse . NewConfigurationSSEKMS ( kmsKeyID )
2021-06-08 12:35:39 -07:00
case models . BucketEncryptionTypeSseDashS3 :
2020-10-25 12:56:23 -07:00
config = sse . NewConfigurationSSES3 ( )
default :
2022-04-28 12:55:06 -07:00
return ErrInvalidEncryptionAlgorithm
2020-10-25 12:56:23 -07:00
}
return client . setBucketEncryption ( ctx , bucketName , config )
}
// disableBucketEncryption will disable bucket for the provided bucket name
func disableBucketEncryption ( ctx context . Context , client MinioClient , bucketName string ) error {
return client . removeBucketEncryption ( ctx , bucketName )
}
func getBucketEncryptionInfo ( ctx context . Context , client MinioClient , bucketName string ) ( * models . BucketEncryptionInfo , error ) {
bucketInfo , err := client . getBucketEncryption ( ctx , bucketName )
if err != nil {
return nil , err
}
if len ( bucketInfo . Rules ) == 0 {
2022-04-28 12:55:06 -07:00
return nil , ErrDefault
2020-10-25 12:56:23 -07:00
}
return & models . BucketEncryptionInfo { Algorithm : bucketInfo . Rules [ 0 ] . Apply . SSEAlgorithm , KmsMasterKeyID : bucketInfo . Rules [ 0 ] . Apply . KmsMasterKeyID } , nil
}
2020-12-03 13:45:45 -06:00
// setBucketRetentionConfig sets object lock configuration on a bucket
func setBucketRetentionConfig ( ctx context . Context , client MinioClient , bucketName string , mode models . ObjectRetentionMode , unit models . ObjectRetentionUnit , validity * int32 ) error {
if validity == nil {
return errors . New ( "retention validity can't be nil" )
}
var retentionMode minio . RetentionMode
switch mode {
case models . ObjectRetentionModeGovernance :
retentionMode = minio . Governance
case models . ObjectRetentionModeCompliance :
retentionMode = minio . Compliance
default :
return errors . New ( "invalid retention mode" )
}
var retentionUnit minio . ValidityUnit
switch unit {
case models . ObjectRetentionUnitDays :
retentionUnit = minio . Days
case models . ObjectRetentionUnitYears :
retentionUnit = minio . Years
default :
return errors . New ( "invalid retention unit" )
}
retentionValidity := uint ( * validity )
return client . setObjectLockConfig ( ctx , bucketName , & retentionMode , & retentionValidity , & retentionUnit )
}
2020-12-15 19:25:43 -06:00
func getBucketRetentionConfig ( ctx context . Context , client MinioClient , bucketName string ) ( * models . GetBucketRetentionConfig , error ) {
m , v , u , err := client . getBucketObjectLockConfig ( ctx , bucketName )
if err != nil {
errResp := minio . ToErrorResponse ( probe . NewError ( err ) . ToGoError ( ) )
if errResp . Code == "ObjectLockConfigurationNotFoundError" {
return & models . GetBucketRetentionConfig { } , nil
}
return nil , err
}
2021-08-09 21:23:40 -07:00
// These values can be empty when all are empty, it means
// object was created with object locking enabled but
// does not have any default object locking configuration.
if m == nil && v == nil && u == nil {
return & models . GetBucketRetentionConfig { } , nil
}
2020-12-15 19:25:43 -06:00
var mode models . ObjectRetentionMode
var unit models . ObjectRetentionUnit
2021-08-09 21:23:40 -07:00
if m != nil {
switch * m {
case minio . Governance :
mode = models . ObjectRetentionModeGovernance
case minio . Compliance :
mode = models . ObjectRetentionModeCompliance
default :
return nil , errors . New ( "invalid retention mode" )
}
2020-12-15 19:25:43 -06:00
}
2021-08-09 21:23:40 -07:00
if u != nil {
switch * u {
case minio . Days :
unit = models . ObjectRetentionUnitDays
case minio . Years :
unit = models . ObjectRetentionUnitYears
default :
return nil , errors . New ( "invalid retention unit" )
}
}
var validity int32
if v != nil {
validity = int32 ( * v )
2020-12-15 19:25:43 -06:00
}
config := & models . GetBucketRetentionConfig {
Mode : mode ,
Unit : unit ,
2021-08-09 21:23:40 -07:00
Validity : validity ,
2020-12-15 19:25:43 -06:00
}
return config , nil
}
2023-08-16 14:18:08 -07:00
func getBucketRewindResponse ( session * models . Principal , params bucketApi . GetBucketRewindParams ) ( * models . RewindResponse , * CodedAPIError ) {
2022-04-28 12:55:06 -07:00
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
2021-06-23 01:10:54 -05:00
defer cancel ( )
2022-05-05 13:44:10 -07:00
prefix := ""
2021-06-23 01:10:54 -05:00
if params . Prefix != nil {
2024-06-05 23:48:27 +02:00
prefix = * params . Prefix
2021-06-23 01:10:54 -05:00
}
2023-06-14 12:36:48 -07:00
s3Client , err := newS3BucketClient ( session , params . BucketName , prefix , getClientIP ( params . HTTPRequest ) )
2021-06-23 01:10:54 -05:00
if err != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , fmt . Errorf ( "error creating S3Client: %v" , err ) )
2021-06-23 01:10:54 -05:00
}
// create a mc S3Client interface implementation
// defining the client to be used
mcClient := mcClient { client : s3Client }
parsedDate , errDate := time . Parse ( time . RFC3339 , params . Date )
if errDate != nil {
2022-04-28 12:55:06 -07:00
return nil , ErrorWithContext ( ctx , errDate )
2021-06-23 01:10:54 -05:00
}
var rewindItems [ ] * models . RewindItem
for content := range mcClient . client . List ( ctx , cmd . ListOptions { TimeRef : parsedDate , WithDeleteMarkers : true } ) {
// build object name
2022-05-05 13:44:10 -07:00
name := strings . ReplaceAll ( content . URL . Path , fmt . Sprintf ( "/%s/" , params . BucketName ) , "" )
2021-06-23 01:10:54 -05:00
listElement := & models . RewindItem {
LastModified : content . Time . Format ( time . RFC3339 ) ,
Size : content . Size ,
VersionID : content . VersionID ,
DeleteFlag : content . IsDeleteMarker ,
Action : "" ,
Name : name ,
}
rewindItems = append ( rewindItems , listElement )
}
return & models . RewindResponse {
Objects : rewindItems ,
} , nil
}
2023-10-19 14:03:14 -07:00
func getMaxShareLinkExpirationResponse ( session * models . Principal , params bucketApi . GetMaxShareLinkExpParams ) ( * models . MaxShareLinkExpResponse , * CodedAPIError ) {
ctx , cancel := context . WithCancel ( params . HTTPRequest . Context ( ) )
defer cancel ( )
maxShareLinkExpSeconds , err := getMaxShareLinkExpirationSeconds ( session )
if err != nil {
return nil , ErrorWithContext ( ctx , err )
}
return & models . MaxShareLinkExpResponse { Exp : swag . Int64 ( maxShareLinkExpSeconds ) } , nil
}
// getMaxShareLinkExpirationSeconds returns the max share link expiration time in seconds which is the sts token expiration time
func getMaxShareLinkExpirationSeconds ( session * models . Principal ) ( int64 , error ) {
creds := getConsoleCredentialsFromSession ( session )
2024-12-30 23:59:10 +05:30
val , err := creds . GetWithContext ( & credentials . CredContext { Client : http . DefaultClient } )
2023-10-19 14:03:14 -07:00
if err != nil {
return 0 , err
}
if val . SignerType . IsAnonymous ( ) {
return 0 , ErrAccessDenied
}
maxShareLinkExp := token . GetConsoleSTSDuration ( )
return int64 ( maxShareLinkExp . Seconds ( ) ) , nil
}