mirror of
https://github.com/versity/versitygw.git
synced 2026-01-08 20:43:07 +00:00
feat: Changed object lock actions interface to put/get []byte
This commit is contained in:
committed by
Ben McClelland
parent
00476ef70c
commit
89755ea5aa
@@ -17,6 +17,7 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -37,6 +38,30 @@ type ObjectLockConfig struct {
|
||||
Retention *types.ObjectLockRetention
|
||||
}
|
||||
|
||||
func ParseBucketLockConfigurationInput(input []byte) ([]byte, error) {
|
||||
var lockConfig types.ObjectLockConfiguration
|
||||
if err := xml.Unmarshal(input, &lockConfig); err != nil {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
config := BucketLockConfig{
|
||||
Enabled: lockConfig.ObjectLockEnabled == types.ObjectLockEnabledEnabled,
|
||||
}
|
||||
|
||||
if lockConfig.Rule != nil && lockConfig.Rule.DefaultRetention != nil {
|
||||
retention := lockConfig.Rule.DefaultRetention
|
||||
if retention.Years != nil && retention.Days != nil {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
config.DefaultRetention = retention
|
||||
now := time.Now()
|
||||
config.CreatedAt = &now
|
||||
}
|
||||
|
||||
return json.Marshal(config)
|
||||
}
|
||||
|
||||
func ParseBucketLockConfigurationOutput(input []byte) (*types.ObjectLockConfiguration, error) {
|
||||
var config BucketLockConfig
|
||||
if err := json.Unmarshal(input, &config); err != nil {
|
||||
@@ -56,6 +81,50 @@ func ParseBucketLockConfigurationOutput(input []byte) (*types.ObjectLockConfigur
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ParseObjectLockRetentionInput(input []byte) ([]byte, error) {
|
||||
var retention types.ObjectLockRetention
|
||||
if err := xml.Unmarshal(input, &retention); err != nil {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
if retention.RetainUntilDate == nil || retention.RetainUntilDate.Before(time.Now()) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrPastObjectLockRetainDate)
|
||||
}
|
||||
switch retention.Mode {
|
||||
case types.ObjectLockRetentionModeCompliance:
|
||||
case types.ObjectLockRetentionModeGovernance:
|
||||
default:
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
return json.Marshal(retention)
|
||||
}
|
||||
|
||||
func ParseObjectLockRetentionOutput(input []byte) (*types.ObjectLockRetention, error) {
|
||||
var retention types.ObjectLockRetention
|
||||
if err := json.Unmarshal(input, &retention); err != nil {
|
||||
return nil, fmt.Errorf("parse object lock retention: %w", err)
|
||||
}
|
||||
|
||||
return &retention, nil
|
||||
}
|
||||
|
||||
func ParseObjectLegalHoldOutput(status *bool) *types.ObjectLockLegalHold {
|
||||
if status == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if *status {
|
||||
return &types.ObjectLockLegalHold{
|
||||
Status: types.ObjectLockLegalHoldStatusOn,
|
||||
}
|
||||
}
|
||||
|
||||
return &types.ObjectLockLegalHold{
|
||||
Status: types.ObjectLockLegalHoldStatusOff,
|
||||
}
|
||||
}
|
||||
|
||||
func CheckObjectAccess(ctx context.Context, bucket, userAccess string, objects []string, isAdminOrRoot bool, be backend.Backend) error {
|
||||
data, err := be.GetObjectLockConfiguration(ctx, bucket)
|
||||
if err != nil {
|
||||
@@ -78,48 +147,58 @@ func CheckObjectAccess(ctx context.Context, bucket, userAccess string, objects [
|
||||
objExists := true
|
||||
|
||||
for _, obj := range objects {
|
||||
retention, err := be.GetObjectRetention(ctx, bucket, obj, "")
|
||||
if err != nil {
|
||||
if errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchKey)) {
|
||||
objExists = false
|
||||
continue
|
||||
}
|
||||
if errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchObjectLockConfiguration)) {
|
||||
continue
|
||||
}
|
||||
|
||||
var checkRetention bool = true
|
||||
retentionData, err := be.GetObjectRetention(ctx, bucket, obj, "")
|
||||
if errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchKey)) {
|
||||
objExists = false
|
||||
continue
|
||||
}
|
||||
if errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchObjectLockConfiguration)) {
|
||||
checkRetention = false
|
||||
}
|
||||
if err != nil && checkRetention {
|
||||
return err
|
||||
}
|
||||
|
||||
if retention.Mode != "" && retention.RetainUntilDate != nil {
|
||||
if retention.RetainUntilDate.After(time.Now()) {
|
||||
switch retention.Mode {
|
||||
case types.ObjectLockRetentionModeGovernance:
|
||||
if !isAdminOrRoot {
|
||||
policy, err := be.GetBucketPolicy(ctx, bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(policy) == 0 {
|
||||
return s3err.GetAPIError(s3err.ErrObjectLocked)
|
||||
}
|
||||
err = verifyBucketPolicy(policy, userAccess, bucket, obj, BypassGovernanceRetentionAction)
|
||||
if err != nil {
|
||||
return s3err.GetAPIError(s3err.ErrObjectLocked)
|
||||
if checkRetention {
|
||||
retention, err := ParseObjectLockRetentionOutput(retentionData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if retention.Mode != "" && retention.RetainUntilDate != nil {
|
||||
if retention.RetainUntilDate.After(time.Now()) {
|
||||
switch retention.Mode {
|
||||
case types.ObjectLockRetentionModeGovernance:
|
||||
if !isAdminOrRoot {
|
||||
policy, err := be.GetBucketPolicy(ctx, bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(policy) == 0 {
|
||||
return s3err.GetAPIError(s3err.ErrObjectLocked)
|
||||
}
|
||||
err = verifyBucketPolicy(policy, userAccess, bucket, obj, BypassGovernanceRetentionAction)
|
||||
if err != nil {
|
||||
return s3err.GetAPIError(s3err.ErrObjectLocked)
|
||||
}
|
||||
}
|
||||
case types.ObjectLockRetentionModeCompliance:
|
||||
return s3err.GetAPIError(s3err.ErrObjectLocked)
|
||||
}
|
||||
case types.ObjectLockRetentionModeCompliance:
|
||||
return s3err.GetAPIError(s3err.ErrObjectLocked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
legalHold, err := be.GetObjectLegalHold(ctx, bucket, obj, "")
|
||||
status, err := be.GetObjectLegalHold(ctx, bucket, obj, "")
|
||||
if errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchObjectLockConfiguration)) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if legalHold.Status == types.ObjectLockLegalHoldStatusOn && !isAdminOrRoot {
|
||||
if *status && !isAdminOrRoot {
|
||||
return s3err.GetAPIError(s3err.ErrObjectLocked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/versity/versitygw/s3err"
|
||||
"github.com/versity/versitygw/s3response"
|
||||
"github.com/versity/versitygw/s3select"
|
||||
@@ -83,12 +82,12 @@ type Backend interface {
|
||||
DeleteObjectTagging(_ context.Context, bucket, object string) error
|
||||
|
||||
// object lock operations
|
||||
PutObjectLockConfiguration(context.Context, *s3.PutObjectLockConfigurationInput) error
|
||||
PutObjectLockConfiguration(_ context.Context, bucket string, config []byte) error
|
||||
GetObjectLockConfiguration(_ context.Context, bucket string) ([]byte, error)
|
||||
PutObjectRetention(context.Context, *s3.PutObjectRetentionInput) error
|
||||
GetObjectRetention(_ context.Context, bucket, object, versionId string) (*types.ObjectLockRetention, error)
|
||||
PutObjectLegalHold(context.Context, *s3.PutObjectLegalHoldInput) error
|
||||
GetObjectLegalHold(_ context.Context, bucket, object, versionId string) (*types.ObjectLockLegalHold, error)
|
||||
PutObjectRetention(_ context.Context, bucket, object, versionId string, retention []byte) error
|
||||
GetObjectRetention(_ context.Context, bucket, object, versionId string) ([]byte, error)
|
||||
PutObjectLegalHold(_ context.Context, bucket, object, versionId string, status bool) error
|
||||
GetObjectLegalHold(_ context.Context, bucket, object, versionId string) (*bool, error)
|
||||
|
||||
// non AWS actions
|
||||
ChangeBucketOwner(_ context.Context, bucket, newOwner string) error
|
||||
@@ -238,22 +237,22 @@ func (BackendUnsupported) DeleteObjectTagging(_ context.Context, bucket, object
|
||||
return s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
|
||||
func (BackendUnsupported) PutObjectLockConfiguration(context.Context, *s3.PutObjectLockConfigurationInput) error {
|
||||
func (BackendUnsupported) PutObjectLockConfiguration(_ context.Context, bucket string, config []byte) error {
|
||||
return s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) GetObjectLockConfiguration(_ context.Context, bucket string) ([]byte, error) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) PutObjectRetention(context.Context, *s3.PutObjectRetentionInput) error {
|
||||
func (BackendUnsupported) PutObjectRetention(_ context.Context, bucket, object, versionId string, retention []byte) error {
|
||||
return s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) GetObjectRetention(_ context.Context, bucket, object, versionId string) (*types.ObjectLockRetention, error) {
|
||||
func (BackendUnsupported) GetObjectRetention(_ context.Context, bucket, object, versionId string) ([]byte, error) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) PutObjectLegalHold(context.Context, *s3.PutObjectLegalHoldInput) error {
|
||||
func (BackendUnsupported) PutObjectLegalHold(_ context.Context, bucket, object, versionId string, status bool) error {
|
||||
return s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) GetObjectLegalHold(_ context.Context, bucket, object, versionId string) (*types.ObjectLockLegalHold, error) {
|
||||
func (BackendUnsupported) GetObjectLegalHold(_ context.Context, bucket, object, versionId string) (*bool, error) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/xattr"
|
||||
"github.com/versity/versitygw/auth"
|
||||
"github.com/versity/versitygw/backend"
|
||||
"github.com/versity/versitygw/backend/meta"
|
||||
@@ -78,7 +76,8 @@ const (
|
||||
etagkey = "etag"
|
||||
policykey = "policy"
|
||||
bucketLockKey = "bucket-lock"
|
||||
objectLockKey = "object-lock"
|
||||
objectRetentionKey = "object-retention"
|
||||
objectLegalHoldKey = "object-legal-hold"
|
||||
)
|
||||
|
||||
type PosixOpts struct {
|
||||
@@ -2015,8 +2014,8 @@ func (p *Posix) DeleteBucketPolicy(ctx context.Context, bucket string) error {
|
||||
return p.PutBucketPolicy(ctx, bucket, nil)
|
||||
}
|
||||
|
||||
func (p *Posix) PutObjectLockConfiguration(_ context.Context, input *s3.PutObjectLockConfigurationInput) error {
|
||||
_, err := os.Stat(*input.Bucket)
|
||||
func (p *Posix) PutObjectLockConfiguration(_ context.Context, bucket string, config []byte) error {
|
||||
_, err := os.Stat(bucket)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
}
|
||||
@@ -2024,30 +2023,8 @@ func (p *Posix) PutObjectLockConfiguration(_ context.Context, input *s3.PutObjec
|
||||
return fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
lockConfig := input.ObjectLockConfiguration
|
||||
|
||||
config := auth.BucketLockConfig{
|
||||
Enabled: lockConfig.ObjectLockEnabled == types.ObjectLockEnabledEnabled,
|
||||
}
|
||||
|
||||
if lockConfig.Rule != nil && lockConfig.Rule.DefaultRetention != nil {
|
||||
retentation := lockConfig.Rule.DefaultRetention
|
||||
if retentation.Years != nil && retentation.Days != nil {
|
||||
return s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
config.DefaultRetention = retentation
|
||||
now := time.Now()
|
||||
config.CreatedAt = &now
|
||||
}
|
||||
|
||||
configParsed, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse object lock config: %w", err)
|
||||
}
|
||||
|
||||
if err := xattr.Set(*input.Bucket, bucketLockKey, configParsed); err != nil {
|
||||
return fmt.Errorf("set tags: %w", err)
|
||||
if err := p.meta.StoreAttribute(bucket, "", bucketLockKey, config); err != nil {
|
||||
return fmt.Errorf("set object lock config: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -2062,7 +2039,7 @@ func (p *Posix) GetObjectLockConfiguration(_ context.Context, bucket string) ([]
|
||||
return nil, fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
cfg, err := xattr.Get(bucket, bucketLockKey)
|
||||
cfg, err := p.meta.RetrieveAttribute(bucket, "", bucketLockKey)
|
||||
if errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrObjectLockConfigurationNotFound)
|
||||
}
|
||||
@@ -2073,8 +2050,8 @@ func (p *Posix) GetObjectLockConfiguration(_ context.Context, bucket string) ([]
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (p *Posix) PutObjectLegalHold(_ context.Context, input *s3.PutObjectLegalHoldInput) error {
|
||||
_, err := os.Stat(*input.Bucket)
|
||||
func (p *Posix) PutObjectLegalHold(_ context.Context, bucket, object, versionId string, status bool) error {
|
||||
_, err := os.Stat(bucket)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
}
|
||||
@@ -2082,7 +2059,7 @@ func (p *Posix) PutObjectLegalHold(_ context.Context, input *s3.PutObjectLegalHo
|
||||
return fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
cfg, err := xattr.Get(*input.Bucket, bucketLockKey)
|
||||
cfg, err := p.meta.RetrieveAttribute(bucket, "", bucketLockKey)
|
||||
if errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return s3err.GetAPIError(s3err.ErrInvalidBucketObjectLockConfiguration)
|
||||
}
|
||||
@@ -2099,40 +2076,14 @@ func (p *Posix) PutObjectLegalHold(_ context.Context, input *s3.PutObjectLegalHo
|
||||
return s3err.GetAPIError(s3err.ErrInvalidBucketObjectLockConfiguration)
|
||||
}
|
||||
|
||||
path := filepath.Join(*input.Bucket, *input.Key)
|
||||
var config auth.ObjectLockConfig
|
||||
|
||||
data, err := xattr.Get(path, objectLockKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return fmt.Errorf("get object lock config: %w", err)
|
||||
}
|
||||
|
||||
config = auth.ObjectLockConfig{}
|
||||
var statusData []byte
|
||||
if status {
|
||||
statusData = []byte{1}
|
||||
} else {
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
return fmt.Errorf("parse object lock data %w", err)
|
||||
}
|
||||
statusData = []byte{0}
|
||||
}
|
||||
|
||||
switch input.LegalHold.Status {
|
||||
case types.ObjectLockLegalHoldStatusOff:
|
||||
config.LegalHoldEnabled = false
|
||||
case types.ObjectLockLegalHoldStatusOn:
|
||||
config.LegalHoldEnabled = true
|
||||
default:
|
||||
return s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal object lock config: %w", err)
|
||||
}
|
||||
|
||||
err = xattr.Set(path, objectLockKey, b)
|
||||
err = p.meta.StoreAttribute(bucket, object, objectLegalHoldKey, statusData)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
@@ -2143,7 +2094,7 @@ func (p *Posix) PutObjectLegalHold(_ context.Context, input *s3.PutObjectLegalHo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Posix) GetObjectLegalHold(_ context.Context, bucket, object, versionId string) (*types.ObjectLockLegalHold, error) {
|
||||
func (p *Posix) GetObjectLegalHold(_ context.Context, bucket, object, versionId string) (*bool, error) {
|
||||
_, err := os.Stat(bucket)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
@@ -2152,7 +2103,7 @@ func (p *Posix) GetObjectLegalHold(_ context.Context, bucket, object, versionId
|
||||
return nil, fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
data, err := xattr.Get(filepath.Join(bucket, object), objectLockKey)
|
||||
data, err := p.meta.RetrieveAttribute(bucket, object, objectLegalHoldKey)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
@@ -2163,24 +2114,13 @@ func (p *Posix) GetObjectLegalHold(_ context.Context, bucket, object, versionId
|
||||
return nil, fmt.Errorf("get object lock config: %w", err)
|
||||
}
|
||||
|
||||
var config auth.ObjectLockConfig
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
return nil, fmt.Errorf("pare object lock config: %w", err)
|
||||
}
|
||||
result := data[0] == 1
|
||||
|
||||
result := &types.ObjectLockLegalHold{}
|
||||
|
||||
if config.LegalHoldEnabled {
|
||||
result.Status = types.ObjectLockLegalHoldStatusOn
|
||||
} else {
|
||||
result.Status = types.ObjectLockLegalHoldStatusOff
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (p *Posix) PutObjectRetention(_ context.Context, input *s3.PutObjectRetentionInput) error {
|
||||
_, err := os.Stat(*input.Bucket)
|
||||
func (p *Posix) PutObjectRetention(_ context.Context, bucket, object, versionId string, retention []byte) error {
|
||||
_, err := os.Stat(bucket)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
}
|
||||
@@ -2188,7 +2128,7 @@ func (p *Posix) PutObjectRetention(_ context.Context, input *s3.PutObjectRetenti
|
||||
return fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
cfg, err := xattr.Get(*input.Bucket, bucketLockKey)
|
||||
cfg, err := p.meta.RetrieveAttribute(bucket, "", bucketLockKey)
|
||||
if errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return s3err.GetAPIError(s3err.ErrInvalidBucketObjectLockConfiguration)
|
||||
}
|
||||
@@ -2205,33 +2145,7 @@ func (p *Posix) PutObjectRetention(_ context.Context, input *s3.PutObjectRetenti
|
||||
return s3err.GetAPIError(s3err.ErrInvalidBucketObjectLockConfiguration)
|
||||
}
|
||||
|
||||
path := filepath.Join(*input.Bucket, *input.Key)
|
||||
var config auth.ObjectLockConfig
|
||||
|
||||
data, err := xattr.Get(path, objectLockKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return fmt.Errorf("get object lock config: %w", err)
|
||||
}
|
||||
|
||||
config = auth.ObjectLockConfig{}
|
||||
} else {
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
return fmt.Errorf("parse object lock data %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
config.Retention = input.Retention
|
||||
|
||||
b, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal object lock config: %w", err)
|
||||
}
|
||||
|
||||
err = xattr.Set(path, objectLockKey, b)
|
||||
err = p.meta.StoreAttribute(bucket, object, objectRetentionKey, retention)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
@@ -2242,7 +2156,7 @@ func (p *Posix) PutObjectRetention(_ context.Context, input *s3.PutObjectRetenti
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Posix) GetObjectRetention(_ context.Context, bucket, object, versionId string) (*types.ObjectLockRetention, error) {
|
||||
func (p *Posix) GetObjectRetention(_ context.Context, bucket, object, versionId string) ([]byte, error) {
|
||||
_, err := os.Stat(bucket)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
@@ -2251,7 +2165,7 @@ func (p *Posix) GetObjectRetention(_ context.Context, bucket, object, versionId
|
||||
return nil, fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
data, err := xattr.Get(filepath.Join(bucket, object), objectLockKey)
|
||||
data, err := p.meta.RetrieveAttribute(bucket, object, objectRetentionKey)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
@@ -2262,16 +2176,7 @@ func (p *Posix) GetObjectRetention(_ context.Context, bucket, object, versionId
|
||||
return nil, fmt.Errorf("get object lock config: %w", err)
|
||||
}
|
||||
|
||||
var config auth.ObjectLockConfig
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
return nil, fmt.Errorf("pare object lock config: %w", err)
|
||||
}
|
||||
|
||||
if config.Retention == nil {
|
||||
return &types.ObjectLockRetention{}, nil
|
||||
}
|
||||
|
||||
return config.Retention, nil
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (p *Posix) ChangeBucketOwner(ctx context.Context, bucket, newOwner string) error {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
"github.com/versity/versitygw/backend"
|
||||
"github.com/versity/versitygw/s3response"
|
||||
"io"
|
||||
@@ -81,13 +80,13 @@ var _ backend.Backend = &BackendMock{}
|
||||
// GetObjectAttributesFunc: func(contextMoqParam context.Context, getObjectAttributesInput *s3.GetObjectAttributesInput) (*s3.GetObjectAttributesOutput, error) {
|
||||
// panic("mock out the GetObjectAttributes method")
|
||||
// },
|
||||
// GetObjectLegalHoldFunc: func(contextMoqParam context.Context, bucket string, object string, versionId string) (*types.ObjectLockLegalHold, error) {
|
||||
// GetObjectLegalHoldFunc: func(contextMoqParam context.Context, bucket string, object string, versionId string) (*bool, error) {
|
||||
// panic("mock out the GetObjectLegalHold method")
|
||||
// },
|
||||
// GetObjectLockConfigurationFunc: func(contextMoqParam context.Context, bucket string) ([]byte, error) {
|
||||
// panic("mock out the GetObjectLockConfiguration method")
|
||||
// },
|
||||
// GetObjectRetentionFunc: func(contextMoqParam context.Context, bucket string, object string, versionId string) (*types.ObjectLockRetention, error) {
|
||||
// GetObjectRetentionFunc: func(contextMoqParam context.Context, bucket string, object string, versionId string) ([]byte, error) {
|
||||
// panic("mock out the GetObjectRetention method")
|
||||
// },
|
||||
// GetObjectTaggingFunc: func(contextMoqParam context.Context, bucket string, object string) (map[string]string, error) {
|
||||
@@ -138,13 +137,13 @@ var _ backend.Backend = &BackendMock{}
|
||||
// PutObjectAclFunc: func(contextMoqParam context.Context, putObjectAclInput *s3.PutObjectAclInput) error {
|
||||
// panic("mock out the PutObjectAcl method")
|
||||
// },
|
||||
// PutObjectLegalHoldFunc: func(contextMoqParam context.Context, putObjectLegalHoldInput *s3.PutObjectLegalHoldInput) error {
|
||||
// PutObjectLegalHoldFunc: func(contextMoqParam context.Context, bucket string, object string, versionId string, status bool) error {
|
||||
// panic("mock out the PutObjectLegalHold method")
|
||||
// },
|
||||
// PutObjectLockConfigurationFunc: func(contextMoqParam context.Context, putObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput) error {
|
||||
// PutObjectLockConfigurationFunc: func(contextMoqParam context.Context, bucket string, config []byte) error {
|
||||
// panic("mock out the PutObjectLockConfiguration method")
|
||||
// },
|
||||
// PutObjectRetentionFunc: func(contextMoqParam context.Context, putObjectRetentionInput *s3.PutObjectRetentionInput) error {
|
||||
// PutObjectRetentionFunc: func(contextMoqParam context.Context, bucket string, object string, versionId string, retention []byte) error {
|
||||
// panic("mock out the PutObjectRetention method")
|
||||
// },
|
||||
// PutObjectTaggingFunc: func(contextMoqParam context.Context, bucket string, object string, tags map[string]string) error {
|
||||
@@ -233,13 +232,13 @@ type BackendMock struct {
|
||||
GetObjectAttributesFunc func(contextMoqParam context.Context, getObjectAttributesInput *s3.GetObjectAttributesInput) (*s3.GetObjectAttributesOutput, error)
|
||||
|
||||
// GetObjectLegalHoldFunc mocks the GetObjectLegalHold method.
|
||||
GetObjectLegalHoldFunc func(contextMoqParam context.Context, bucket string, object string, versionId string) (*types.ObjectLockLegalHold, error)
|
||||
GetObjectLegalHoldFunc func(contextMoqParam context.Context, bucket string, object string, versionId string) (*bool, error)
|
||||
|
||||
// GetObjectLockConfigurationFunc mocks the GetObjectLockConfiguration method.
|
||||
GetObjectLockConfigurationFunc func(contextMoqParam context.Context, bucket string) ([]byte, error)
|
||||
|
||||
// GetObjectRetentionFunc mocks the GetObjectRetention method.
|
||||
GetObjectRetentionFunc func(contextMoqParam context.Context, bucket string, object string, versionId string) (*types.ObjectLockRetention, error)
|
||||
GetObjectRetentionFunc func(contextMoqParam context.Context, bucket string, object string, versionId string) ([]byte, error)
|
||||
|
||||
// GetObjectTaggingFunc mocks the GetObjectTagging method.
|
||||
GetObjectTaggingFunc func(contextMoqParam context.Context, bucket string, object string) (map[string]string, error)
|
||||
@@ -290,13 +289,13 @@ type BackendMock struct {
|
||||
PutObjectAclFunc func(contextMoqParam context.Context, putObjectAclInput *s3.PutObjectAclInput) error
|
||||
|
||||
// PutObjectLegalHoldFunc mocks the PutObjectLegalHold method.
|
||||
PutObjectLegalHoldFunc func(contextMoqParam context.Context, putObjectLegalHoldInput *s3.PutObjectLegalHoldInput) error
|
||||
PutObjectLegalHoldFunc func(contextMoqParam context.Context, bucket string, object string, versionId string, status bool) error
|
||||
|
||||
// PutObjectLockConfigurationFunc mocks the PutObjectLockConfiguration method.
|
||||
PutObjectLockConfigurationFunc func(contextMoqParam context.Context, putObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput) error
|
||||
PutObjectLockConfigurationFunc func(contextMoqParam context.Context, bucket string, config []byte) error
|
||||
|
||||
// PutObjectRetentionFunc mocks the PutObjectRetention method.
|
||||
PutObjectRetentionFunc func(contextMoqParam context.Context, putObjectRetentionInput *s3.PutObjectRetentionInput) error
|
||||
PutObjectRetentionFunc func(contextMoqParam context.Context, bucket string, object string, versionId string, retention []byte) error
|
||||
|
||||
// PutObjectTaggingFunc mocks the PutObjectTagging method.
|
||||
PutObjectTaggingFunc func(contextMoqParam context.Context, bucket string, object string, tags map[string]string) error
|
||||
@@ -615,22 +614,36 @@ type BackendMock struct {
|
||||
PutObjectLegalHold []struct {
|
||||
// ContextMoqParam is the contextMoqParam argument value.
|
||||
ContextMoqParam context.Context
|
||||
// PutObjectLegalHoldInput is the putObjectLegalHoldInput argument value.
|
||||
PutObjectLegalHoldInput *s3.PutObjectLegalHoldInput
|
||||
// Bucket is the bucket argument value.
|
||||
Bucket string
|
||||
// Object is the object argument value.
|
||||
Object string
|
||||
// VersionId is the versionId argument value.
|
||||
VersionId string
|
||||
// Status is the status argument value.
|
||||
Status bool
|
||||
}
|
||||
// PutObjectLockConfiguration holds details about calls to the PutObjectLockConfiguration method.
|
||||
PutObjectLockConfiguration []struct {
|
||||
// ContextMoqParam is the contextMoqParam argument value.
|
||||
ContextMoqParam context.Context
|
||||
// PutObjectLockConfigurationInput is the putObjectLockConfigurationInput argument value.
|
||||
PutObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput
|
||||
// Bucket is the bucket argument value.
|
||||
Bucket string
|
||||
// Config is the config argument value.
|
||||
Config []byte
|
||||
}
|
||||
// PutObjectRetention holds details about calls to the PutObjectRetention method.
|
||||
PutObjectRetention []struct {
|
||||
// ContextMoqParam is the contextMoqParam argument value.
|
||||
ContextMoqParam context.Context
|
||||
// PutObjectRetentionInput is the putObjectRetentionInput argument value.
|
||||
PutObjectRetentionInput *s3.PutObjectRetentionInput
|
||||
// Bucket is the bucket argument value.
|
||||
Bucket string
|
||||
// Object is the object argument value.
|
||||
Object string
|
||||
// VersionId is the versionId argument value.
|
||||
VersionId string
|
||||
// Retention is the retention argument value.
|
||||
Retention []byte
|
||||
}
|
||||
// PutObjectTagging holds details about calls to the PutObjectTagging method.
|
||||
PutObjectTagging []struct {
|
||||
@@ -1429,7 +1442,7 @@ func (mock *BackendMock) GetObjectAttributesCalls() []struct {
|
||||
}
|
||||
|
||||
// GetObjectLegalHold calls GetObjectLegalHoldFunc.
|
||||
func (mock *BackendMock) GetObjectLegalHold(contextMoqParam context.Context, bucket string, object string, versionId string) (*types.ObjectLockLegalHold, error) {
|
||||
func (mock *BackendMock) GetObjectLegalHold(contextMoqParam context.Context, bucket string, object string, versionId string) (*bool, error) {
|
||||
if mock.GetObjectLegalHoldFunc == nil {
|
||||
panic("BackendMock.GetObjectLegalHoldFunc: method is nil but Backend.GetObjectLegalHold was just called")
|
||||
}
|
||||
@@ -1509,7 +1522,7 @@ func (mock *BackendMock) GetObjectLockConfigurationCalls() []struct {
|
||||
}
|
||||
|
||||
// GetObjectRetention calls GetObjectRetentionFunc.
|
||||
func (mock *BackendMock) GetObjectRetention(contextMoqParam context.Context, bucket string, object string, versionId string) (*types.ObjectLockRetention, error) {
|
||||
func (mock *BackendMock) GetObjectRetention(contextMoqParam context.Context, bucket string, object string, versionId string) ([]byte, error) {
|
||||
if mock.GetObjectRetentionFunc == nil {
|
||||
panic("BackendMock.GetObjectRetentionFunc: method is nil but Backend.GetObjectRetention was just called")
|
||||
}
|
||||
@@ -2145,21 +2158,27 @@ func (mock *BackendMock) PutObjectAclCalls() []struct {
|
||||
}
|
||||
|
||||
// PutObjectLegalHold calls PutObjectLegalHoldFunc.
|
||||
func (mock *BackendMock) PutObjectLegalHold(contextMoqParam context.Context, putObjectLegalHoldInput *s3.PutObjectLegalHoldInput) error {
|
||||
func (mock *BackendMock) PutObjectLegalHold(contextMoqParam context.Context, bucket string, object string, versionId string, status bool) error {
|
||||
if mock.PutObjectLegalHoldFunc == nil {
|
||||
panic("BackendMock.PutObjectLegalHoldFunc: method is nil but Backend.PutObjectLegalHold was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectLegalHoldInput *s3.PutObjectLegalHoldInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Object string
|
||||
VersionId string
|
||||
Status bool
|
||||
}{
|
||||
ContextMoqParam: contextMoqParam,
|
||||
PutObjectLegalHoldInput: putObjectLegalHoldInput,
|
||||
ContextMoqParam: contextMoqParam,
|
||||
Bucket: bucket,
|
||||
Object: object,
|
||||
VersionId: versionId,
|
||||
Status: status,
|
||||
}
|
||||
mock.lockPutObjectLegalHold.Lock()
|
||||
mock.calls.PutObjectLegalHold = append(mock.calls.PutObjectLegalHold, callInfo)
|
||||
mock.lockPutObjectLegalHold.Unlock()
|
||||
return mock.PutObjectLegalHoldFunc(contextMoqParam, putObjectLegalHoldInput)
|
||||
return mock.PutObjectLegalHoldFunc(contextMoqParam, bucket, object, versionId, status)
|
||||
}
|
||||
|
||||
// PutObjectLegalHoldCalls gets all the calls that were made to PutObjectLegalHold.
|
||||
@@ -2167,12 +2186,18 @@ func (mock *BackendMock) PutObjectLegalHold(contextMoqParam context.Context, put
|
||||
//
|
||||
// len(mockedBackend.PutObjectLegalHoldCalls())
|
||||
func (mock *BackendMock) PutObjectLegalHoldCalls() []struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectLegalHoldInput *s3.PutObjectLegalHoldInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Object string
|
||||
VersionId string
|
||||
Status bool
|
||||
} {
|
||||
var calls []struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectLegalHoldInput *s3.PutObjectLegalHoldInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Object string
|
||||
VersionId string
|
||||
Status bool
|
||||
}
|
||||
mock.lockPutObjectLegalHold.RLock()
|
||||
calls = mock.calls.PutObjectLegalHold
|
||||
@@ -2181,21 +2206,23 @@ func (mock *BackendMock) PutObjectLegalHoldCalls() []struct {
|
||||
}
|
||||
|
||||
// PutObjectLockConfiguration calls PutObjectLockConfigurationFunc.
|
||||
func (mock *BackendMock) PutObjectLockConfiguration(contextMoqParam context.Context, putObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput) error {
|
||||
func (mock *BackendMock) PutObjectLockConfiguration(contextMoqParam context.Context, bucket string, config []byte) error {
|
||||
if mock.PutObjectLockConfigurationFunc == nil {
|
||||
panic("BackendMock.PutObjectLockConfigurationFunc: method is nil but Backend.PutObjectLockConfiguration was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Config []byte
|
||||
}{
|
||||
ContextMoqParam: contextMoqParam,
|
||||
PutObjectLockConfigurationInput: putObjectLockConfigurationInput,
|
||||
ContextMoqParam: contextMoqParam,
|
||||
Bucket: bucket,
|
||||
Config: config,
|
||||
}
|
||||
mock.lockPutObjectLockConfiguration.Lock()
|
||||
mock.calls.PutObjectLockConfiguration = append(mock.calls.PutObjectLockConfiguration, callInfo)
|
||||
mock.lockPutObjectLockConfiguration.Unlock()
|
||||
return mock.PutObjectLockConfigurationFunc(contextMoqParam, putObjectLockConfigurationInput)
|
||||
return mock.PutObjectLockConfigurationFunc(contextMoqParam, bucket, config)
|
||||
}
|
||||
|
||||
// PutObjectLockConfigurationCalls gets all the calls that were made to PutObjectLockConfiguration.
|
||||
@@ -2203,12 +2230,14 @@ func (mock *BackendMock) PutObjectLockConfiguration(contextMoqParam context.Cont
|
||||
//
|
||||
// len(mockedBackend.PutObjectLockConfigurationCalls())
|
||||
func (mock *BackendMock) PutObjectLockConfigurationCalls() []struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Config []byte
|
||||
} {
|
||||
var calls []struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Config []byte
|
||||
}
|
||||
mock.lockPutObjectLockConfiguration.RLock()
|
||||
calls = mock.calls.PutObjectLockConfiguration
|
||||
@@ -2217,21 +2246,27 @@ func (mock *BackendMock) PutObjectLockConfigurationCalls() []struct {
|
||||
}
|
||||
|
||||
// PutObjectRetention calls PutObjectRetentionFunc.
|
||||
func (mock *BackendMock) PutObjectRetention(contextMoqParam context.Context, putObjectRetentionInput *s3.PutObjectRetentionInput) error {
|
||||
func (mock *BackendMock) PutObjectRetention(contextMoqParam context.Context, bucket string, object string, versionId string, retention []byte) error {
|
||||
if mock.PutObjectRetentionFunc == nil {
|
||||
panic("BackendMock.PutObjectRetentionFunc: method is nil but Backend.PutObjectRetention was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectRetentionInput *s3.PutObjectRetentionInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Object string
|
||||
VersionId string
|
||||
Retention []byte
|
||||
}{
|
||||
ContextMoqParam: contextMoqParam,
|
||||
PutObjectRetentionInput: putObjectRetentionInput,
|
||||
ContextMoqParam: contextMoqParam,
|
||||
Bucket: bucket,
|
||||
Object: object,
|
||||
VersionId: versionId,
|
||||
Retention: retention,
|
||||
}
|
||||
mock.lockPutObjectRetention.Lock()
|
||||
mock.calls.PutObjectRetention = append(mock.calls.PutObjectRetention, callInfo)
|
||||
mock.lockPutObjectRetention.Unlock()
|
||||
return mock.PutObjectRetentionFunc(contextMoqParam, putObjectRetentionInput)
|
||||
return mock.PutObjectRetentionFunc(contextMoqParam, bucket, object, versionId, retention)
|
||||
}
|
||||
|
||||
// PutObjectRetentionCalls gets all the calls that were made to PutObjectRetention.
|
||||
@@ -2239,12 +2274,18 @@ func (mock *BackendMock) PutObjectRetention(contextMoqParam context.Context, put
|
||||
//
|
||||
// len(mockedBackend.PutObjectRetentionCalls())
|
||||
func (mock *BackendMock) PutObjectRetentionCalls() []struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectRetentionInput *s3.PutObjectRetentionInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Object string
|
||||
VersionId string
|
||||
Retention []byte
|
||||
} {
|
||||
var calls []struct {
|
||||
ContextMoqParam context.Context
|
||||
PutObjectRetentionInput *s3.PutObjectRetentionInput
|
||||
ContextMoqParam context.Context
|
||||
Bucket string
|
||||
Object string
|
||||
VersionId string
|
||||
Retention []byte
|
||||
}
|
||||
mock.lockPutObjectRetention.RLock()
|
||||
calls = mock.calls.PutObjectRetention
|
||||
|
||||
@@ -151,7 +151,17 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
data, err := c.be.GetObjectRetention(ctx.Context(), bucket, key, versionId)
|
||||
return SendXMLResponse(ctx, data, err,
|
||||
if err != nil {
|
||||
return SendXMLResponse(ctx, data, err,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "GetObjectRetention",
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
retention, err := auth.ParseObjectLockRetentionOutput(data)
|
||||
return SendXMLResponse(ctx, retention, err,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "GetObjectRetention",
|
||||
@@ -179,7 +189,7 @@ func (c S3ApiController) GetActions(ctx *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
data, err := c.be.GetObjectLegalHold(ctx.Context(), bucket, key, versionId)
|
||||
return SendXMLResponse(ctx, data, err,
|
||||
return SendXMLResponse(ctx, auth.ParseObjectLegalHoldOutput(data), err,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "GetObjectLegalHold",
|
||||
@@ -941,16 +951,6 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
|
||||
if ctx.Request().URI().QueryArgs().Has("object-lock") {
|
||||
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
|
||||
|
||||
var input types.ObjectLockConfiguration
|
||||
if err := xml.Unmarshal(ctx.Body(), &input); err != nil {
|
||||
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidRequest),
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "PutObjectLockConfiguration",
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
if err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
|
||||
Acl: parsedAcl,
|
||||
AclPermission: types.PermissionWrite,
|
||||
@@ -967,10 +967,17 @@ func (c S3ApiController) PutBucketActions(ctx *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
err := c.be.PutObjectLockConfiguration(ctx.Context(), &s3.PutObjectLockConfigurationInput{
|
||||
Bucket: &bucket,
|
||||
ObjectLockConfiguration: &input,
|
||||
})
|
||||
config, err := auth.ParseBucketLockConfigurationInput(ctx.Body())
|
||||
if err != nil {
|
||||
return SendResponse(ctx, err,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "PutObjectLockConfiguration",
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
err = c.be.PutObjectLockConfiguration(ctx.Context(), bucket, config)
|
||||
return SendResponse(ctx, err,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
@@ -1211,7 +1218,6 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error {
|
||||
keyEnd := ctx.Params("*1")
|
||||
uploadId := ctx.Query("uploadId")
|
||||
versionId := ctx.Query("versionId")
|
||||
bypassGovernanceRetention := ctx.Get("X-Amz-Bypass-Governance-Retention")
|
||||
acct := ctx.Locals("account").(auth.Account)
|
||||
isRoot := ctx.Locals("isRoot").(bool)
|
||||
parsedAcl := ctx.Locals("parsedAcl").(auth.ACL)
|
||||
@@ -1313,24 +1319,6 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
if ctx.Request().URI().QueryArgs().Has("retention") {
|
||||
var retention types.ObjectLockRetention
|
||||
if err := xml.Unmarshal(ctx.Body(), &retention); err != nil {
|
||||
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidRequest), &MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "PutObjectRetention",
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
if retention.RetainUntilDate == nil || retention.RetainUntilDate.Before(time.Now()) {
|
||||
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrPastObjectLockRetainDate),
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "PutObjectRetention",
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
if err := auth.VerifyAccess(ctx.Context(), c.be, auth.AccessOptions{
|
||||
Acl: parsedAcl,
|
||||
AclPermission: types.PermissionWrite,
|
||||
@@ -1348,15 +1336,16 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
pass := bypassGovernanceRetention == "True"
|
||||
retention, err := auth.ParseObjectLockRetentionInput(ctx.Body())
|
||||
if err != nil {
|
||||
return SendResponse(ctx, err, &MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "PutObjectRetention",
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
err := c.be.PutObjectRetention(ctx.Context(), &s3.PutObjectRetentionInput{
|
||||
Bucket: &bucket,
|
||||
Key: &keyStart,
|
||||
VersionId: &versionId,
|
||||
Retention: &retention,
|
||||
BypassGovernanceRetention: &pass,
|
||||
})
|
||||
err = c.be.PutObjectRetention(ctx.Context(), bucket, keyStart, versionId, retention)
|
||||
return SendResponse(ctx, err, &MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "PutObjectRetention",
|
||||
@@ -1391,12 +1380,7 @@ func (c S3ApiController) PutActions(ctx *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
err := c.be.PutObjectLegalHold(ctx.Context(), &s3.PutObjectLegalHoldInput{
|
||||
Bucket: &bucket,
|
||||
Key: &keyStart,
|
||||
VersionId: &versionId,
|
||||
LegalHold: &legalHold,
|
||||
})
|
||||
err := c.be.PutObjectLegalHold(ctx.Context(), bucket, keyStart, versionId, legalHold.Status == types.ObjectLockLegalHoldStatusOn)
|
||||
return SendResponse(ctx, err, &MetaOpts{
|
||||
Logger: c.logger,
|
||||
Action: "PutObjectLegalHold",
|
||||
|
||||
@@ -205,11 +205,18 @@ func TestS3ApiController_GetActions(t *testing.T) {
|
||||
GetObjectTaggingFunc: func(_ context.Context, bucket, object string) (map[string]string, error) {
|
||||
return map[string]string{"hello": "world"}, nil
|
||||
},
|
||||
GetObjectRetentionFunc: func(contextMoqParam context.Context, bucket, object, versionId string) (*types.ObjectLockRetention, error) {
|
||||
return &types.ObjectLockRetention{}, nil
|
||||
GetObjectRetentionFunc: func(contextMoqParam context.Context, bucket, object, versionId string) ([]byte, error) {
|
||||
result, err := json.Marshal(types.ObjectLockRetention{
|
||||
Mode: types.ObjectLockRetentionModeCompliance,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
},
|
||||
GetObjectLegalHoldFunc: func(contextMoqParam context.Context, bucket, object, versionId string) (*types.ObjectLockLegalHold, error) {
|
||||
return &types.ObjectLockLegalHold{}, nil
|
||||
GetObjectLegalHoldFunc: func(contextMoqParam context.Context, bucket, object, versionId string) (*bool, error) {
|
||||
result := true
|
||||
return &result, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -657,7 +664,7 @@ func TestS3ApiController_PutBucketActions(t *testing.T) {
|
||||
PutBucketPolicyFunc: func(contextMoqParam context.Context, bucket string, policy []byte) error {
|
||||
return nil
|
||||
},
|
||||
PutObjectLockConfigurationFunc: func(contextMoqParam context.Context, putObjectLockConfigurationInput *s3.PutObjectLockConfigurationInput) error {
|
||||
PutObjectLockConfigurationFunc: func(contextMoqParam context.Context, bucket string, config []byte) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
@@ -919,10 +926,10 @@ func TestS3ApiController_PutActions(t *testing.T) {
|
||||
UploadPartCopyFunc: func(context.Context, *s3.UploadPartCopyInput) (s3response.CopyObjectResult, error) {
|
||||
return s3response.CopyObjectResult{}, nil
|
||||
},
|
||||
PutObjectLegalHoldFunc: func(contextMoqParam context.Context, putObjectLegalHoldInput *s3.PutObjectLegalHoldInput) error {
|
||||
PutObjectLegalHoldFunc: func(contextMoqParam context.Context, bucket, object, versionId string, status bool) error {
|
||||
return nil
|
||||
},
|
||||
PutObjectRetentionFunc: func(contextMoqParam context.Context, putObjectRetentionInput *s3.PutObjectRetentionInput) error {
|
||||
PutObjectRetentionFunc: func(contextMoqParam context.Context, bucket, object, versionId string, retention []byte) error {
|
||||
return nil
|
||||
},
|
||||
GetObjectLockConfigurationFunc: func(contextMoqParam context.Context, bucket string) ([]byte, error) {
|
||||
|
||||
Reference in New Issue
Block a user