storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/policy/condition/binaryequalsfunc.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2018 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package condition
    18  
    19  import (
    20  	"encoding/base64"
    21  	"fmt"
    22  	"net/http"
    23  	"sort"
    24  
    25  	"github.com/minio/minio-go/v7/pkg/s3utils"
    26  	"github.com/minio/minio-go/v7/pkg/set"
    27  )
    28  
    29  func toBinaryEqualsFuncString(n name, key Key, values set.StringSet) string {
    30  	valueStrings := values.ToSlice()
    31  	sort.Strings(valueStrings)
    32  
    33  	return fmt.Sprintf("%v:%v:%v", n, key, valueStrings)
    34  }
    35  
    36  // binaryEqualsFunc - String equals function. It checks whether value by Key in given
    37  // values map is in condition values.
    38  // For example,
    39  //   - if values = ["mybucket/foo"], at evaluate() it returns whether string
    40  //     in value map for Key is in values.
    41  type binaryEqualsFunc struct {
    42  	k      Key
    43  	values set.StringSet
    44  }
    45  
    46  // evaluate() - evaluates to check whether value by Key in given values is in
    47  // condition values.
    48  func (f binaryEqualsFunc) evaluate(values map[string][]string) bool {
    49  	requestValue, ok := values[http.CanonicalHeaderKey(f.k.Name())]
    50  	if !ok {
    51  		requestValue = values[f.k.Name()]
    52  	}
    53  
    54  	fvalues := f.values.ApplyFunc(substFuncFromValues(values))
    55  	return !fvalues.Intersection(set.CreateStringSet(requestValue...)).IsEmpty()
    56  }
    57  
    58  // key() - returns condition key which is used by this condition function.
    59  func (f binaryEqualsFunc) key() Key {
    60  	return f.k
    61  }
    62  
    63  // name() - returns "BinaryEquals" condition name.
    64  func (f binaryEqualsFunc) name() name {
    65  	return binaryEquals
    66  }
    67  
    68  func (f binaryEqualsFunc) String() string {
    69  	return toBinaryEqualsFuncString(binaryEquals, f.k, f.values)
    70  }
    71  
    72  // toMap - returns map representation of this function.
    73  func (f binaryEqualsFunc) toMap() map[Key]ValueSet {
    74  	if !f.k.IsValid() {
    75  		return nil
    76  	}
    77  
    78  	values := NewValueSet()
    79  	for _, value := range f.values.ToSlice() {
    80  		values.Add(NewStringValue(base64.StdEncoding.EncodeToString([]byte(value))))
    81  	}
    82  
    83  	return map[Key]ValueSet{
    84  		f.k: values,
    85  	}
    86  }
    87  
    88  func validateBinaryEqualsValues(n name, key Key, values set.StringSet) error {
    89  	vslice := values.ToSlice()
    90  	for _, s := range vslice {
    91  		sbytes, err := base64.StdEncoding.DecodeString(s)
    92  		if err != nil {
    93  			return err
    94  		}
    95  		values.Remove(s)
    96  		s = string(sbytes)
    97  		switch key {
    98  		case S3XAmzCopySource:
    99  			bucket, object := path2BucketAndObject(s)
   100  			if object == "" {
   101  				return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzCopySource, n)
   102  			}
   103  			if err = s3utils.CheckValidBucketName(bucket); err != nil {
   104  				return err
   105  			}
   106  		case S3XAmzServerSideEncryption, S3XAmzServerSideEncryptionCustomerAlgorithm:
   107  			if s != "AES256" {
   108  				return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzServerSideEncryption, n)
   109  			}
   110  		case S3XAmzMetadataDirective:
   111  			if s != "COPY" && s != "REPLACE" {
   112  				return fmt.Errorf("invalid value '%v' for '%v' for %v condition", s, S3XAmzMetadataDirective, n)
   113  			}
   114  		case S3XAmzContentSha256:
   115  			if s == "" {
   116  				return fmt.Errorf("invalid empty value for '%v' for %v condition", S3XAmzContentSha256, n)
   117  			}
   118  		}
   119  		values.Add(s)
   120  	}
   121  
   122  	return nil
   123  }
   124  
   125  // newBinaryEqualsFunc - returns new BinaryEquals function.
   126  func newBinaryEqualsFunc(key Key, values ValueSet) (Function, error) {
   127  	valueStrings, err := valuesToStringSlice(binaryEquals, values)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	return NewBinaryEqualsFunc(key, valueStrings...)
   133  }
   134  
   135  // NewBinaryEqualsFunc - returns new BinaryEquals function.
   136  func NewBinaryEqualsFunc(key Key, values ...string) (Function, error) {
   137  	sset := set.CreateStringSet(values...)
   138  	if err := validateBinaryEqualsValues(binaryEquals, key, sset); err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	return &binaryEqualsFunc{key, sset}, nil
   143  }