1/*
2Package validation provides methods for validating parameter value using reflection.
3*/
4package validation
5
6// Copyright 2017 Microsoft Corporation
7//
8//  Licensed under the Apache License, Version 2.0 (the "License");
9//  you may not use this file except in compliance with the License.
10//  You may obtain a copy of the License at
11//
12//      http://www.apache.org/licenses/LICENSE-2.0
13//
14//  Unless required by applicable law or agreed to in writing, software
15//  distributed under the License is distributed on an "AS IS" BASIS,
16//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17//  See the License for the specific language governing permissions and
18//  limitations under the License.
19
20import (
21	"fmt"
22	"reflect"
23	"regexp"
24	"strings"
25)
26
27// Constraint stores constraint name, target field name
28// Rule and chain validations.
29type Constraint struct {
30
31	// Target field name for validation.
32	Target string
33
34	// Constraint name e.g. minLength, MaxLength, Pattern, etc.
35	Name string
36
37	// Rule for constraint e.g. greater than 10, less than 5 etc.
38	Rule interface{}
39
40	// Chain Validations for struct type
41	Chain []Constraint
42}
43
44// Validation stores parameter-wise validation.
45type Validation struct {
46	TargetValue interface{}
47	Constraints []Constraint
48}
49
50// Constraint list
51const (
52	Empty            = "Empty"
53	Null             = "Null"
54	ReadOnly         = "ReadOnly"
55	Pattern          = "Pattern"
56	MaxLength        = "MaxLength"
57	MinLength        = "MinLength"
58	MaxItems         = "MaxItems"
59	MinItems         = "MinItems"
60	MultipleOf       = "MultipleOf"
61	UniqueItems      = "UniqueItems"
62	InclusiveMaximum = "InclusiveMaximum"
63	ExclusiveMaximum = "ExclusiveMaximum"
64	ExclusiveMinimum = "ExclusiveMinimum"
65	InclusiveMinimum = "InclusiveMinimum"
66)
67
68// Validate method validates constraints on parameter
69// passed in validation array.
70func Validate(m []Validation) error {
71	for _, item := range m {
72		v := reflect.ValueOf(item.TargetValue)
73		for _, constraint := range item.Constraints {
74			var err error
75			switch v.Kind() {
76			case reflect.Ptr:
77				err = validatePtr(v, constraint)
78			case reflect.String:
79				err = validateString(v, constraint)
80			case reflect.Struct:
81				err = validateStruct(v, constraint)
82			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
83				err = validateInt(v, constraint)
84			case reflect.Float32, reflect.Float64:
85				err = validateFloat(v, constraint)
86			case reflect.Array, reflect.Slice, reflect.Map:
87				err = validateArrayMap(v, constraint)
88			default:
89				err = createError(v, constraint, fmt.Sprintf("unknown type %v", v.Kind()))
90			}
91
92			if err != nil {
93				return err
94			}
95		}
96	}
97	return nil
98}
99
100func validateStruct(x reflect.Value, v Constraint, name ...string) error {
101	//Get field name from target name which is in format a.b.c
102	s := strings.Split(v.Target, ".")
103	f := x.FieldByName(s[len(s)-1])
104	if isZero(f) {
105		return createError(x, v, fmt.Sprintf("field %q doesn't exist", v.Target))
106	}
107
108	return Validate([]Validation{
109		{
110			TargetValue: getInterfaceValue(f),
111			Constraints: []Constraint{v},
112		},
113	})
114}
115
116func validatePtr(x reflect.Value, v Constraint) error {
117	if v.Name == ReadOnly {
118		if !x.IsNil() {
119			return createError(x.Elem(), v, "readonly parameter; must send as nil or empty in request")
120		}
121		return nil
122	}
123	if x.IsNil() {
124		return checkNil(x, v)
125	}
126	if v.Chain != nil {
127		return Validate([]Validation{
128			{
129				TargetValue: getInterfaceValue(x.Elem()),
130				Constraints: v.Chain,
131			},
132		})
133	}
134	return nil
135}
136
137func validateInt(x reflect.Value, v Constraint) error {
138	i := x.Int()
139	r, ok := toInt64(v.Rule)
140	if !ok {
141		return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.Name, v.Rule))
142	}
143	switch v.Name {
144	case MultipleOf:
145		if i%r != 0 {
146			return createError(x, v, fmt.Sprintf("value must be a multiple of %v", r))
147		}
148	case ExclusiveMinimum:
149		if i <= r {
150			return createError(x, v, fmt.Sprintf("value must be greater than %v", r))
151		}
152	case ExclusiveMaximum:
153		if i >= r {
154			return createError(x, v, fmt.Sprintf("value must be less than %v", r))
155		}
156	case InclusiveMinimum:
157		if i < r {
158			return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r))
159		}
160	case InclusiveMaximum:
161		if i > r {
162			return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r))
163		}
164	default:
165		return createError(x, v, fmt.Sprintf("constraint %v is not applicable for type integer", v.Name))
166	}
167	return nil
168}
169
170func validateFloat(x reflect.Value, v Constraint) error {
171	f := x.Float()
172	r, ok := v.Rule.(float64)
173	if !ok {
174		return createError(x, v, fmt.Sprintf("rule must be float value for %v constraint; got: %v", v.Name, v.Rule))
175	}
176	switch v.Name {
177	case ExclusiveMinimum:
178		if f <= r {
179			return createError(x, v, fmt.Sprintf("value must be greater than %v", r))
180		}
181	case ExclusiveMaximum:
182		if f >= r {
183			return createError(x, v, fmt.Sprintf("value must be less than %v", r))
184		}
185	case InclusiveMinimum:
186		if f < r {
187			return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r))
188		}
189	case InclusiveMaximum:
190		if f > r {
191			return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r))
192		}
193	default:
194		return createError(x, v, fmt.Sprintf("constraint %s is not applicable for type float", v.Name))
195	}
196	return nil
197}
198
199func validateString(x reflect.Value, v Constraint) error {
200	s := x.String()
201	switch v.Name {
202	case Empty:
203		if len(s) == 0 {
204			return checkEmpty(x, v)
205		}
206	case Pattern:
207		reg, err := regexp.Compile(v.Rule.(string))
208		if err != nil {
209			return createError(x, v, err.Error())
210		}
211		if !reg.MatchString(s) {
212			return createError(x, v, fmt.Sprintf("value doesn't match pattern %v", v.Rule))
213		}
214	case MaxLength:
215		if _, ok := v.Rule.(int); !ok {
216			return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.Name, v.Rule))
217		}
218		if len(s) > v.Rule.(int) {
219			return createError(x, v, fmt.Sprintf("value length must be less than or equal to %v", v.Rule))
220		}
221	case MinLength:
222		if _, ok := v.Rule.(int); !ok {
223			return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.Name, v.Rule))
224		}
225		if len(s) < v.Rule.(int) {
226			return createError(x, v, fmt.Sprintf("value length must be greater than or equal to %v", v.Rule))
227		}
228	case ReadOnly:
229		if len(s) > 0 {
230			return createError(reflect.ValueOf(s), v, "readonly parameter; must send as nil or empty in request")
231		}
232	default:
233		return createError(x, v, fmt.Sprintf("constraint %s is not applicable to string type", v.Name))
234	}
235
236	if v.Chain != nil {
237		return Validate([]Validation{
238			{
239				TargetValue: getInterfaceValue(x),
240				Constraints: v.Chain,
241			},
242		})
243	}
244	return nil
245}
246
247func validateArrayMap(x reflect.Value, v Constraint) error {
248	switch v.Name {
249	case Null:
250		if x.IsNil() {
251			return checkNil(x, v)
252		}
253	case Empty:
254		if x.IsNil() || x.Len() == 0 {
255			return checkEmpty(x, v)
256		}
257	case MaxItems:
258		if _, ok := v.Rule.(int); !ok {
259			return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.Name, v.Rule))
260		}
261		if x.Len() > v.Rule.(int) {
262			return createError(x, v, fmt.Sprintf("maximum item limit is %v; got: %v", v.Rule, x.Len()))
263		}
264	case MinItems:
265		if _, ok := v.Rule.(int); !ok {
266			return createError(x, v, fmt.Sprintf("rule must be integer for %v constraint; got: %v", v.Name, v.Rule))
267		}
268		if x.Len() < v.Rule.(int) {
269			return createError(x, v, fmt.Sprintf("minimum item limit is %v; got: %v", v.Rule, x.Len()))
270		}
271	case UniqueItems:
272		if x.Kind() == reflect.Array || x.Kind() == reflect.Slice {
273			if !checkForUniqueInArray(x) {
274				return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.Target, x))
275			}
276		} else if x.Kind() == reflect.Map {
277			if !checkForUniqueInMap(x) {
278				return createError(x, v, fmt.Sprintf("all items in parameter %q must be unique; got:%v", v.Target, x))
279			}
280		} else {
281			return createError(x, v, fmt.Sprintf("type must be array, slice or map for constraint %v; got: %v", v.Name, x.Kind()))
282		}
283	case ReadOnly:
284		if x.Len() != 0 {
285			return createError(x, v, "readonly parameter; must send as nil or empty in request")
286		}
287	case Pattern:
288		reg, err := regexp.Compile(v.Rule.(string))
289		if err != nil {
290			return createError(x, v, err.Error())
291		}
292		keys := x.MapKeys()
293		for _, k := range keys {
294			if !reg.MatchString(k.String()) {
295				return createError(k, v, fmt.Sprintf("map key doesn't match pattern %v", v.Rule))
296			}
297		}
298	default:
299		return createError(x, v, fmt.Sprintf("constraint %v is not applicable to array, slice and map type", v.Name))
300	}
301
302	if v.Chain != nil {
303		return Validate([]Validation{
304			{
305				TargetValue: getInterfaceValue(x),
306				Constraints: v.Chain,
307			},
308		})
309	}
310	return nil
311}
312
313func checkNil(x reflect.Value, v Constraint) error {
314	if _, ok := v.Rule.(bool); !ok {
315		return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.Name, v.Rule))
316	}
317	if v.Rule.(bool) {
318		return createError(x, v, "value can not be null; required parameter")
319	}
320	return nil
321}
322
323func checkEmpty(x reflect.Value, v Constraint) error {
324	if _, ok := v.Rule.(bool); !ok {
325		return createError(x, v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.Name, v.Rule))
326	}
327
328	if v.Rule.(bool) {
329		return createError(x, v, "value can not be null or empty; required parameter")
330	}
331	return nil
332}
333
334func checkForUniqueInArray(x reflect.Value) bool {
335	if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 {
336		return false
337	}
338	arrOfInterface := make([]interface{}, x.Len())
339
340	for i := 0; i < x.Len(); i++ {
341		arrOfInterface[i] = x.Index(i).Interface()
342	}
343
344	m := make(map[interface{}]bool)
345	for _, val := range arrOfInterface {
346		if m[val] {
347			return false
348		}
349		m[val] = true
350	}
351	return true
352}
353
354func checkForUniqueInMap(x reflect.Value) bool {
355	if x == reflect.Zero(reflect.TypeOf(x)) || x.Len() == 0 {
356		return false
357	}
358	mapOfInterface := make(map[interface{}]interface{}, x.Len())
359
360	keys := x.MapKeys()
361	for _, k := range keys {
362		mapOfInterface[k.Interface()] = x.MapIndex(k).Interface()
363	}
364
365	m := make(map[interface{}]bool)
366	for _, val := range mapOfInterface {
367		if m[val] {
368			return false
369		}
370		m[val] = true
371	}
372	return true
373}
374
375func getInterfaceValue(x reflect.Value) interface{} {
376	if x.Kind() == reflect.Invalid {
377		return nil
378	}
379	return x.Interface()
380}
381
382func isZero(x interface{}) bool {
383	return x == reflect.Zero(reflect.TypeOf(x)).Interface()
384}
385
386func createError(x reflect.Value, v Constraint, err string) error {
387	return fmt.Errorf("autorest/validation: validation failed: parameter=%s constraint=%s value=%#v details: %s",
388		v.Target, v.Name, getInterfaceValue(x), err)
389}
390
391func toInt64(v interface{}) (int64, bool) {
392	if i64, ok := v.(int64); ok {
393		return i64, true
394	}
395	// older generators emit max constants as int, so if int64 fails fall back to int
396	if i32, ok := v.(int); ok {
397		return int64(i32), true
398	}
399	return 0, false
400}
401