-
Notifications
You must be signed in to change notification settings - Fork 771
/
searchAttrValidator.go
134 lines (121 loc) · 5.66 KB
/
searchAttrValidator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to qvom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, qvETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package validator
import (
"fmt"
"github.com/uber/cadence/common"
"github.com/uber/cadence/common/definition"
"github.com/uber/cadence/common/dynamicconfig"
"github.com/uber/cadence/common/log"
"github.com/uber/cadence/common/log/tag"
"github.com/uber/cadence/common/types"
)
// SearchAttributesValidator is used to validate search attributes
type SearchAttributesValidator struct {
logger log.Logger
validSearchAttributes dynamicconfig.MapPropertyFn
searchAttributesNumberOfKeysLimit dynamicconfig.IntPropertyFnWithDomainFilter
searchAttributesSizeOfValueLimit dynamicconfig.IntPropertyFnWithDomainFilter
searchAttributesTotalSizeLimit dynamicconfig.IntPropertyFnWithDomainFilter
}
// NewSearchAttributesValidator create SearchAttributesValidator
func NewSearchAttributesValidator(
logger log.Logger,
validSearchAttributes dynamicconfig.MapPropertyFn,
searchAttributesNumberOfKeysLimit dynamicconfig.IntPropertyFnWithDomainFilter,
searchAttributesSizeOfValueLimit dynamicconfig.IntPropertyFnWithDomainFilter,
searchAttributesTotalSizeLimit dynamicconfig.IntPropertyFnWithDomainFilter,
) *SearchAttributesValidator {
return &SearchAttributesValidator{
logger: logger,
validSearchAttributes: validSearchAttributes,
searchAttributesNumberOfKeysLimit: searchAttributesNumberOfKeysLimit,
searchAttributesSizeOfValueLimit: searchAttributesSizeOfValueLimit,
searchAttributesTotalSizeLimit: searchAttributesTotalSizeLimit,
}
}
// ValidateSearchAttributes validate search attributes are valid for writing and not exceed limits
func (sv *SearchAttributesValidator) ValidateSearchAttributes(input *types.SearchAttributes, domain string) error {
if input == nil {
return nil
}
// verify: number of keys <= limit
fields := input.GetIndexedFields()
lengthOfFields := len(fields)
if lengthOfFields > sv.searchAttributesNumberOfKeysLimit(domain) {
sv.logger.WithTags(tag.Number(int64(lengthOfFields)), tag.WorkflowDomainName(domain)).
Error("number of keys in search attributes exceed limit")
return &types.BadRequestError{Message: fmt.Sprintf("number of keys %d exceed limit", lengthOfFields)}
}
totalSize := 0
validAttr := sv.validSearchAttributes()
for key, val := range fields {
// verify: key is whitelisted
if !sv.isValidSearchAttributesKey(validAttr, key) {
sv.logger.WithTags(tag.ESKey(key), tag.WorkflowDomainName(domain)).
Error("invalid search attribute key")
return &types.BadRequestError{Message: fmt.Sprintf("%s is not a valid search attribute key", key)}
}
// verify: value has the correct type
if !sv.isValidSearchAttributesValue(validAttr, key, val) {
sv.logger.WithTags(tag.ESKey(key), tag.ESValue(val), tag.WorkflowDomainName(domain)).
Error("invalid search attribute value")
return &types.BadRequestError{Message: fmt.Sprintf("%s is not a valid search attribute value for key %s", val, key)}
}
// verify: key is not system reserved
if definition.IsSystemIndexedKey(key) {
sv.logger.WithTags(tag.ESKey(key), tag.WorkflowDomainName(domain)).
Error("illegal update of system reserved attribute")
return &types.BadRequestError{Message: fmt.Sprintf("%s is read-only Cadence reservered attribute", key)}
}
// verify: size of single value <= limit
if len(val) > sv.searchAttributesSizeOfValueLimit(domain) {
sv.logger.WithTags(tag.ESKey(key), tag.Number(int64(len(val))), tag.WorkflowDomainName(domain)).
Error("value size of search attribute exceed limit")
return &types.BadRequestError{Message: fmt.Sprintf("size limit exceed for key %s", key)}
}
totalSize += len(key) + len(val)
}
// verify: total size <= limit
if totalSize > sv.searchAttributesTotalSizeLimit(domain) {
sv.logger.WithTags(tag.Number(int64(totalSize)), tag.WorkflowDomainName(domain)).
Error("total size of search attributes exceed limit")
return &types.BadRequestError{Message: fmt.Sprintf("total size %d exceed limit", totalSize)}
}
return nil
}
// isValidSearchAttributesKey return true if key is registered
func (sv *SearchAttributesValidator) isValidSearchAttributesKey(
validAttr map[string]interface{},
key string,
) bool {
_, isValidKey := validAttr[key]
return isValidKey
}
// isValidSearchAttributesValue return true if value has the correct representation for the attribute key
func (sv *SearchAttributesValidator) isValidSearchAttributesValue(
validAttr map[string]interface{},
key string,
value []byte,
) bool {
valueType := common.ConvertIndexedValueTypeToThriftType(validAttr[key], sv.logger)
_, err := common.DeserializeSearchAttributeValue(value, valueType)
return err == nil
}