Upstream versity/versitygw state of the touched files before 070b030237
This commit is contained in:
1 parent
08d5acf963
commit
79e4cf7bca
2 files changed
+723
-51
No files matched your search
@@ -0,0 +1,723 @@
|
|||||||
|
// Copyright 2023 Versity Software
|
||||||
|
// This file is licensed under the Apache License, Version 2.0
|
||||||
|
// (the "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
"github.com/versity/versitygw/auth"
|
||||||
|
"github.com/versity/versitygw/s3api/utils"
|
||||||
|
"github.com/versity/versitygw/s3response"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketTagging(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketTaggingAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, err := c.be.GetBucketTagging(ctx.RequestCtx(), bucket)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
resp := s3response.Tagging{
|
||||||
|
TagSet: s3response.TagSet{
|
||||||
|
Tags: make([]s3response.Tag, 0, len(tags)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, val := range tags {
|
||||||
|
resp.TagSet.Tags = append(resp.TagSet.Tags,
|
||||||
|
s3response.Tag{Key: key, Value: val})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Response{
|
||||||
|
Data: resp,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketOwnershipControls(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketOwnershipControlsAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.GetBucketOwnershipControls(ctx.RequestCtx(), bucket)
|
||||||
|
return &Response{
|
||||||
|
Data: s3response.OwnershipControls{
|
||||||
|
Rules: []types.OwnershipControlsRule{
|
||||||
|
{
|
||||||
|
ObjectOwnership: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketVersioning(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketVersioningAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.GetBucketVersioning(ctx.RequestCtx(), bucket)
|
||||||
|
return &Response{
|
||||||
|
Data: data,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketCors(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketCorsAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.GetBucketCors(ctx.RequestCtx(), bucket)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := auth.ParseCORSOutput(data)
|
||||||
|
return &Response{
|
||||||
|
Data: output,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketWebsite(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketWebsiteAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.GetBucketWebsite(ctx.RequestCtx(), bucket)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := s3response.ParseWebsiteConfigOutput(data)
|
||||||
|
return &Response{
|
||||||
|
Data: output,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketPolicy(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketPolicyAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.GetBucketPolicy(ctx.RequestCtx(), bucket)
|
||||||
|
return &Response{
|
||||||
|
Data: data,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketPolicyStatus(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketPolicyStatusAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
policyRaw, err := c.be.GetBucketPolicy(ctx.RequestCtx(), bucket)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
policy, err := auth.ParsePolicyDocument(policyRaw)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
isPublic := policy.IsPublic()
|
||||||
|
|
||||||
|
return &Response{
|
||||||
|
Data: types.PolicyStatus{
|
||||||
|
IsPublic: &isPublic,
|
||||||
|
},
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) ListObjectVersions(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
// url values
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
prefix := ctx.Query("prefix")
|
||||||
|
delimiter := ctx.Query("delimiter")
|
||||||
|
maxkeysStr := ctx.Query("max-keys")
|
||||||
|
keyMarker := ctx.Query("key-marker")
|
||||||
|
versionIdMarker := ctx.Query("version-id-marker")
|
||||||
|
// context keys
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.ListBucketVersionsAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
maxkeys, err := utils.ParseMaxLimiter(maxkeysStr, utils.LimiterTypeVersionsMaxKeys)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.ListObjectVersions(ctx.RequestCtx(),
|
||||||
|
&s3.ListObjectVersionsInput{
|
||||||
|
Bucket: &bucket,
|
||||||
|
Delimiter: &delimiter,
|
||||||
|
KeyMarker: &keyMarker,
|
||||||
|
MaxKeys: &maxkeys,
|
||||||
|
Prefix: &prefix,
|
||||||
|
VersionIdMarker: &versionIdMarker,
|
||||||
|
})
|
||||||
|
return &Response{
|
||||||
|
Data: data,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetObjectLockConfiguration(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
// url values
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
// context keys
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketObjectLockConfigurationAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.GetObjectLockConfiguration(ctx.RequestCtx(), bucket)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := auth.ParseBucketLockConfigurationOutput(data)
|
||||||
|
return &Response{
|
||||||
|
Data: resp,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) GetBucketAcl(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
// url values
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
// context keys
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionReadAcp,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketAclAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.be.GetBucketAcl(ctx.RequestCtx(),
|
||||||
|
&s3.GetBucketAclInput{Bucket: &bucket})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := auth.ParseACLOutput(data, parsedAcl.Owner)
|
||||||
|
return &Response{
|
||||||
|
Data: res,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) ListMultipartUploads(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
// url values
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
prefix := ctx.Query("prefix")
|
||||||
|
delimiter := ctx.Query("delimiter")
|
||||||
|
keyMarker := ctx.Query("key-marker")
|
||||||
|
maxUploadsStr := ctx.Query("max-uploads")
|
||||||
|
uploadIdMarker := ctx.Query("upload-id-marker")
|
||||||
|
// context keys
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.ListBucketMultipartUploadsAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
maxUploads, err := utils.ParseMaxLimiter(maxUploadsStr, utils.LimiterTypeMaxUploads)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
res, err := c.be.ListMultipartUploads(ctx.RequestCtx(),
|
||||||
|
&s3.ListMultipartUploadsInput{
|
||||||
|
Bucket: &bucket,
|
||||||
|
Delimiter: &delimiter,
|
||||||
|
Prefix: &prefix,
|
||||||
|
UploadIdMarker: &uploadIdMarker,
|
||||||
|
MaxUploads: &maxUploads,
|
||||||
|
KeyMarker: &keyMarker,
|
||||||
|
})
|
||||||
|
return &Response{
|
||||||
|
Data: res,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) ListObjectsV2(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
// url values
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
prefix := ctx.Query("prefix")
|
||||||
|
cToken := ctx.Query("continuation-token")
|
||||||
|
sAfter := ctx.Query("start-after")
|
||||||
|
delimiter := ctx.Query("delimiter")
|
||||||
|
maxkeysStr := ctx.Query("max-keys")
|
||||||
|
fetchOwner := strings.EqualFold(ctx.Query("fetch-owner"), "true")
|
||||||
|
// context locals
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
region, ok := utils.ContextKeyRegion.Get(ctx).(string)
|
||||||
|
if !ok {
|
||||||
|
region = defaultRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.ListBucketAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
maxkeys, err := utils.ParseMaxLimiter(maxkeysStr, utils.LimiterTypeMaxKeys)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.be.ListObjectsV2(ctx.RequestCtx(),
|
||||||
|
&s3.ListObjectsV2Input{
|
||||||
|
Bucket: &bucket,
|
||||||
|
Prefix: &prefix,
|
||||||
|
ContinuationToken: &cToken,
|
||||||
|
Delimiter: &delimiter,
|
||||||
|
MaxKeys: &maxkeys,
|
||||||
|
StartAfter: &sAfter,
|
||||||
|
FetchOwner: &fetchOwner,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Response{
|
||||||
|
Headers: map[string]*string{
|
||||||
|
"x-amz-bucket-region": ®ion,
|
||||||
|
},
|
||||||
|
Data: res,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c S3ApiController) ListObjects(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
// url values
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
prefix := ctx.Query("prefix")
|
||||||
|
marker := ctx.Query("marker")
|
||||||
|
delimiter := ctx.Query("delimiter")
|
||||||
|
maxkeysStr := ctx.Query("max-keys")
|
||||||
|
// context locals
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
region, ok := utils.ContextKeyRegion.Get(ctx).(string)
|
||||||
|
if !ok {
|
||||||
|
region = defaultRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.ListBucketAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
maxkeys, err := utils.ParseMaxLimiter(maxkeysStr, utils.LimiterTypeMaxKeys)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.be.ListObjects(ctx.RequestCtx(),
|
||||||
|
&s3.ListObjectsInput{
|
||||||
|
Bucket: &bucket,
|
||||||
|
Prefix: &prefix,
|
||||||
|
Marker: &marker,
|
||||||
|
Delimiter: &delimiter,
|
||||||
|
MaxKeys: &maxkeys,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// S3 echoes the request marker back in the response, and includes the
|
||||||
|
// element even when the request carried no marker. Backends return a nil
|
||||||
|
// pointer for an empty marker, which encoding/xml drops entirely, so
|
||||||
|
// restore it here for every backend.
|
||||||
|
if res.Marker == nil {
|
||||||
|
res.Marker = &marker
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Response{
|
||||||
|
Headers: map[string]*string{
|
||||||
|
"x-amz-bucket-region": ®ion,
|
||||||
|
},
|
||||||
|
Data: res,
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBucketLocation handles GET /:bucket?location
|
||||||
|
func (c S3ApiController) GetBucketLocation(ctx fiber.Ctx) (*Response, error) {
|
||||||
|
bucket := ctx.Params("bucket")
|
||||||
|
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||||
|
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||||
|
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||||
|
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||||
|
|
||||||
|
err := c.verifyAccess(ctx, auth.AccessOptions{
|
||||||
|
Acl: parsedAcl,
|
||||||
|
AclPermission: auth.PermissionRead,
|
||||||
|
IsRoot: isRoot,
|
||||||
|
Acc: acct,
|
||||||
|
Bucket: bucket,
|
||||||
|
Actions: []auth.Action{auth.GetBucketLocationAction},
|
||||||
|
IsPublicRequest: isPublicBucket,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify bucket existence/access via backend HeadBucket
|
||||||
|
_, err = c.be.HeadBucket(ctx.RequestCtx(), &s3.HeadBucketInput{Bucket: &bucket})
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// pick up configured region from locals (set by router middleware)
|
||||||
|
region, _ := ctx.Locals("region").(string)
|
||||||
|
value := ®ion
|
||||||
|
if region == "us-east-1" {
|
||||||
|
value = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Response{
|
||||||
|
Data: s3response.LocationConstraint{
|
||||||
|
Value: value,
|
||||||
|
},
|
||||||
|
MetaOpts: &MetaOptions{
|
||||||
|
BucketOwner: parsedAcl.Owner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -152,57 +152,6 @@ func ListMultipartUploads_max_uploads(s *S3Conf) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListMultipartUploads_next_markers_not_truncated(s *S3Conf) error {
|
|
||||||
testName := "ListMultipartUploads_next_markers_not_truncated"
|
|
||||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
|
||||||
uploads := []types.MultipartUpload{}
|
|
||||||
for _, key := range []string{"bar", "baz", "foo"} {
|
|
||||||
out, err := createMp(s3client, bucket, key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
uploads = append(uploads, types.MultipartUpload{
|
|
||||||
UploadId: out.UploadId,
|
|
||||||
Key: out.Key,
|
|
||||||
StorageClass: types.StorageClassStandard,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
last := uploads[len(uploads)-1]
|
|
||||||
|
|
||||||
// a single page still reports the last upload in the next markers,
|
|
||||||
// with the default max-uploads and with one equal to the upload count
|
|
||||||
for _, maxUploads := range []*int32{nil, getPtr(int32(len(uploads)))} {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
|
||||||
out, err := s3client.ListMultipartUploads(ctx, &s3.ListMultipartUploadsInput{
|
|
||||||
Bucket: &bucket,
|
|
||||||
MaxUploads: maxUploads,
|
|
||||||
})
|
|
||||||
cancel()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if out.IsTruncated == nil || *out.IsTruncated {
|
|
||||||
return fmt.Errorf("expected a non-truncated response")
|
|
||||||
}
|
|
||||||
if ok := compareMultipartUploads(out.Uploads, uploads); !ok {
|
|
||||||
return fmt.Errorf("expected multipart uploads to be %v, instead got %v",
|
|
||||||
uploads, out.Uploads)
|
|
||||||
}
|
|
||||||
if getString(out.NextKeyMarker) != getString(last.Key) {
|
|
||||||
return fmt.Errorf("expected next-key-marker to be %v, instead got %v",
|
|
||||||
getString(last.Key), getString(out.NextKeyMarker))
|
|
||||||
}
|
|
||||||
if getString(out.NextUploadIdMarker) != getString(last.UploadId) {
|
|
||||||
return fmt.Errorf("expected next-upload-id-marker to be %v, instead got %v",
|
|
||||||
getString(last.UploadId), getString(out.NextUploadIdMarker))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListMultipartUploads_exceeding_max_uploads(s *S3Conf) error {
|
func ListMultipartUploads_exceeding_max_uploads(s *S3Conf) error {
|
||||||
testName := "ListMultipartUploads_exceeding_max_uploads"
|
testName := "ListMultipartUploads_exceeding_max_uploads"
|
||||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||||
|
|||||||
Reference in new issue
Block a user