From 5f5fd0bc48d9ca28cd7d55af1c9b57a940c6fd9c Mon Sep 17 00:00:00 2001 From: Lapshin Vitaliy Date: Mon, 20 Jun 2022 11:32:58 +0300 Subject: [PATCH] validate tags on copy object and add regex for validating tags --- weed/s3api/s3api_object_copy_handlers.go | 26 +++++++----- weed/s3api/s3api_object_copy_handlers_test.go | 2 +- weed/s3api/s3api_object_tagging_handlers.go | 18 ++------- weed/s3api/tags.go | 40 +++++++++++++++++++ 4 files changed, 60 insertions(+), 26 deletions(-) diff --git a/weed/s3api/s3api_object_copy_handlers.go b/weed/s3api/s3api_object_copy_handlers.go index 9157748f6..8e62deb94 100644 --- a/weed/s3api/s3api_object_copy_handlers.go +++ b/weed/s3api/s3api_object_copy_handlers.go @@ -45,7 +45,11 @@ func (s3a *S3ApiServer) CopyObjectHandler(w http.ResponseWriter, r *http.Request s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource) return } - entry.Extended = processMetadataBytes(r.Header, entry.Extended, replaceMeta, replaceTagging) + entry.Extended, err = processMetadataBytes(r.Header, entry.Extended, replaceMeta, replaceTagging) + if err != nil { + glog.Errorf("CopyObjectHandler ValidateTags error %s: %v", r.URL, err) + s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag) + } err = s3a.touch(dir, name, entry) if err != nil { s3err.WriteErrorResponse(w, r, s3err.ErrInvalidCopySource) @@ -252,7 +256,7 @@ func processMetadata(reqHeader, existing http.Header, replaceMeta, replaceTaggin return } -func processMetadataBytes(reqHeader http.Header, existing map[string][]byte, replaceMeta, replaceTagging bool) (metadata map[string][]byte) { +func processMetadataBytes(reqHeader http.Header, existing map[string][]byte, replaceMeta, replaceTagging bool) (metadata map[string][]byte, err error) { metadata = make(map[string][]byte) if sc := existing[s3_constants.AmzStorageClass]; len(sc) > 0 { @@ -277,16 +281,18 @@ func processMetadataBytes(reqHeader http.Header, existing map[string][]byte, rep } } } - if replaceTagging { if tags := reqHeader.Get(s3_constants.AmzObjectTagging); tags != "" { - for _, v := range strings.Split(tags, "&") { - tag := strings.Split(v, "=") - if len(tag) == 2 { - metadata[s3_constants.AmzObjectTagging+"-"+tag[0]] = []byte(tag[1]) - } else if len(tag) == 1 { - metadata[s3_constants.AmzObjectTagging+"-"+tag[0]] = nil - } + parsedTags, err := parseTagsHeader(tags) + if err != nil { + return nil, err + } + err = validateTags(parsedTags) + if err != nil { + return nil, err + } + for k, v := range parsedTags { + metadata[s3_constants.AmzObjectTagging+"-"+k] = []byte(v) } } } else { diff --git a/weed/s3api/s3api_object_copy_handlers_test.go b/weed/s3api/s3api_object_copy_handlers_test.go index 610b29a6b..3cb2b0562 100644 --- a/weed/s3api/s3api_object_copy_handlers_test.go +++ b/weed/s3api/s3api_object_copy_handlers_test.go @@ -367,7 +367,7 @@ func TestProcessMetadataBytes(t *testing.T) { reqHeader := transferHToHeader(tc.request) existing := transferHToBytesArr(tc.existing) replaceMeta, replaceTagging := replaceDirective(reqHeader) - extends := processMetadataBytes(reqHeader, existing, replaceMeta, replaceTagging) + extends, _ := processMetadataBytes(reqHeader, existing, replaceMeta, replaceTagging) result := transferBytesArrToH(extends) fmtTagging(result, tc.want) diff --git a/weed/s3api/s3api_object_tagging_handlers.go b/weed/s3api/s3api_object_tagging_handlers.go index 9fde0309c..35da1cc20 100644 --- a/weed/s3api/s3api_object_tagging_handlers.go +++ b/weed/s3api/s3api_object_tagging_handlers.go @@ -62,22 +62,10 @@ func (s3a *S3ApiServer) PutObjectTaggingHandler(w http.ResponseWriter, r *http.R return } tags := tagging.ToTags() - if len(tags) > 10 { - glog.Errorf("PutObjectTaggingHandler tags %s: %d tags more than 10", r.URL, len(tags)) + err = validateTags(tags) + if err != nil { + glog.Errorf("PutObjectTaggingHandler ValidateTags error %s: %v", r.URL, err) s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag) - return - } - for k, v := range tags { - if len(k) > 128 { - glog.Errorf("PutObjectTaggingHandler tags %s: tag key %s longer than 128", r.URL, k) - s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag) - return - } - if len(v) > 256 { - glog.Errorf("PutObjectTaggingHandler tags %s: tag value %s longer than 256", r.URL, v) - s3err.WriteErrorResponse(w, r, s3err.ErrInvalidTag) - return - } } if err = s3a.setTags(dir, name, tagging.ToTags()); err != nil { diff --git a/weed/s3api/tags.go b/weed/s3api/tags.go index 979e5a80c..06c9e4b80 100644 --- a/weed/s3api/tags.go +++ b/weed/s3api/tags.go @@ -2,6 +2,9 @@ package s3api import ( "encoding/xml" + "fmt" + "regexp" + "strings" ) type Tag struct { @@ -37,3 +40,40 @@ func FromTags(tags map[string]string) (t *Tagging) { } return } + +func parseTagsHeader(tags string) (map[string]string, error) { + var parsedTags map[string]string + for _, v := range strings.Split(tags, "&") { + tag := strings.Split(v, "=") + if len(tag) == 2 { + parsedTags[tag[0]] = tag[1] + } else if len(tag) == 1 { + parsedTags[tag[0]] = "" + } + } + return nil, nil +} + +func validateTags(tags map[string]string) error { + if len(tags) > 10 { + return fmt.Errorf("validate tags: %d tags more than 10", len(tags)) + } + for k, v := range tags { + if len(k) > 128 { + return fmt.Errorf("validate tags: tag key %s longer than 128", k) + } + validateKey, err := regexp.MatchString(`^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$`, k) + if !validateKey && err != nil { + return fmt.Errorf("validate tags key %s error %w ", k, err) + } + if len(v) > 256 { + return fmt.Errorf("validate tags: tag value %s longer than 256", v) + } + validateValue, err := regexp.MatchString(`^([\p{L}\p{Z}\p{N}_.:/=+\-@]*)$`, v) + if !validateValue && err != nil { + return fmt.Errorf("validate tags value %s error %w ", v, err) + } + } + + return nil +}