1 // SPDX-License-Identifier: Apache-2.0
\r
2 // Copyright (c) 2020 Intel Corporation
\r
20 log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
\r
21 pkgerrors "github.com/pkg/errors"
\r
22 "github.com/xeipuuv/gojsonschema"
\r
23 "k8s.io/apimachinery/pkg/util/validation"
\r
26 func IsTarGz(r io.Reader) error {
\r
27 //Check if it is a valid gz
\r
28 gzf, err := gzip.NewReader(r)
\r
30 return pkgerrors.Wrap(err, "Invalid gzip format")
\r
33 //Check if it is a valid tar file
\r
34 //Unfortunately this can only be done by inspecting all the tar contents
\r
35 tarR := tar.NewReader(gzf)
\r
39 header, err := tarR.Next()
\r
42 //Check if we have just a gzip file without a tar archive inside
\r
44 return pkgerrors.New("Empty or non-existant Tar file found")
\r
51 return pkgerrors.Errorf("Error reading tar file %s", err.Error())
\r
54 //Check if files are of type directory and regular file
\r
55 if header.Typeflag != tar.TypeDir &&
\r
56 header.Typeflag != tar.TypeReg {
\r
57 return pkgerrors.Errorf("Unknown header in tar %s, %s",
\r
58 header.Name, string(header.Typeflag))
\r
67 func IsIpv4Cidr(cidr string) error {
\r
68 ip, _, err := net.ParseCIDR(cidr)
\r
69 if err != nil || ip.To4() == nil {
\r
70 return pkgerrors.Wrapf(err, "could not parse ipv4 cidr %v", cidr)
\r
75 func IsIp(ip string) error {
\r
76 addr := net.ParseIP(ip)
\r
78 return pkgerrors.Errorf("invalid ip address %v", ip)
\r
83 func IsIpv4(ip string) error {
\r
84 addr := net.ParseIP(ip)
\r
85 if addr == nil || addr.To4() == nil {
\r
86 return pkgerrors.Errorf("invalid ipv4 address %v", ip)
\r
91 func IsMac(mac string) error {
\r
92 _, err := net.ParseMAC(mac)
\r
94 return pkgerrors.Errorf("invalid MAC address %v", mac)
\r
99 // default name check - matches valid label value with addtion that length > 0
\r
100 func IsValidName(name string) []string {
\r
103 errs = validation.IsValidLabelValue(name)
\r
104 if len(name) == 0 {
\r
105 errs = append(errs, "name must have non-zero length")
\r
110 const VALID_NAME_STR string = "NAME"
\r
112 var validNameRegEx = regexp.MustCompile("^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$")
\r
114 const VALID_ALPHA_STR string = "ALPHA"
\r
116 var validAlphaStrRegEx = regexp.MustCompile("^[A-Za-z]*$")
\r
118 const VALID_ALPHANUM_STR string = "ALPHANUM"
\r
120 var validAlphaNumStrRegEx = regexp.MustCompile("^[A-Za-z0-9]*$")
\r
122 // doesn't verify valid base64 length - just checks for proper base64 characters
\r
123 const VALID_BASE64_STR string = "BASE64"
\r
125 var validBase64StrRegEx = regexp.MustCompile("^[A-Za-z0-9+/]+={0,2}$")
\r
127 const VALID_ANY_STR string = "ANY"
\r
129 var validAnyStrRegEx = regexp.MustCompile("(?s)^.*$")
\r
131 // string check - validates for conformance to provided lengths and specified content
\r
132 // min and max - the string
\r
133 // if format string provided - check against matching predefined
\r
134 func IsValidString(str string, min, max int, format string) []string {
\r
138 errs = append(errs, "Invalid string length constraints - min is greater than max")
\r
142 if len(str) < min {
\r
143 errs = append(errs, "string length is less than the minimum constraint")
\r
146 if len(str) > max {
\r
147 errs = append(errs, "string length is greater than the maximum constraint")
\r
152 case VALID_ALPHA_STR:
\r
153 if !validAlphaStrRegEx.MatchString(str) {
\r
154 errs = append(errs, "string does not match the alpha only constraint")
\r
156 case VALID_ALPHANUM_STR:
\r
157 if !validAlphaNumStrRegEx.MatchString(str) {
\r
158 errs = append(errs, "string does not match the alphanumeric only constraint")
\r
160 case VALID_NAME_STR:
\r
161 if !validNameRegEx.MatchString(str) {
\r
162 errs = append(errs, "string does not match the valid k8s name constraint")
\r
164 case VALID_BASE64_STR:
\r
165 if !validBase64StrRegEx.MatchString(str) {
\r
166 errs = append(errs, "string does not match the valid base64 characters constraint")
\r
168 if len(str)%4 != 0 {
\r
169 errs = append(errs, "base64 string length should be a multiple of 4")
\r
171 case VALID_ANY_STR:
\r
172 if !validAnyStrRegEx.MatchString(str) {
\r
173 errs = append(errs, "string does not match the any characters constraint")
\r
176 // invalid string format supplied
\r
177 errs = append(errs, "an invalid string constraint was supplied")
\r
183 // validate that label conforms to kubernetes label conventions
\r
184 // general label format expected is:
\r
185 // "<labelprefix>/<labelname>=<Labelvalue>"
\r
186 // where labelprefix matches DNS1123Subdomain format
\r
187 // labelname matches DNS1123Label format
\r
189 // Input labels are allowed to match following formats:
\r
190 // "<DNS1123Subdomain>/<DNS1123Label>=<Labelvalue>"
\r
191 // "<DNS1123Label>=<LabelValue>"
\r
193 func IsValidLabel(label string) []string {
\r
194 var labelerrs []string
\r
196 expectLabelName := false
\r
197 expectLabelPrefix := false
\r
199 // split label up into prefix, name and value
\r
200 // format: prefix/name=value
\r
201 var labelprefix, labelname, labelvalue string
\r
203 kv := strings.SplitN(label, "=", 2)
\r
209 pn := strings.SplitN(kv[0], "/", 2)
\r
214 labelprefix = pn[0]
\r
216 expectLabelPrefix = true
\r
219 // if "=" was in the label input, then expect a non-zero length name
\r
220 expectLabelName = true
\r
223 // check label prefix validity - prefix is optional
\r
224 if len(labelprefix) > 0 {
\r
225 errs := validation.IsDNS1123Subdomain(labelprefix)
\r
227 labelerrs = append(labelerrs, "Invalid label prefix - label=["+label+"%], labelprefix=["+labelprefix+"], errors: ")
\r
228 for _, err := range errs {
\r
229 labelerrs = append(labelerrs, err)
\r
232 } else if expectLabelPrefix {
\r
233 labelerrs = append(labelerrs, "Invalid label prefix - label=["+label+"%], labelprefix=["+labelprefix+"]")
\r
235 if expectLabelName {
\r
236 errs := validation.IsDNS1123Label(labelname)
\r
238 labelerrs = append(labelerrs, "Invalid label name - label=["+label+"%], labelname=["+labelname+"], errors: ")
\r
239 for _, err := range errs {
\r
240 labelerrs = append(labelerrs, err)
\r
244 if len(labelvalue) > 0 {
\r
245 errs := validation.IsValidLabelValue(labelvalue)
\r
247 labelerrs = append(labelerrs, "Invalid label value - label=["+label+"%], labelvalue=["+labelvalue+"], errors: ")
\r
248 for _, err := range errs {
\r
249 labelerrs = append(labelerrs, err)
\r
253 // expect a non-zero value
\r
254 labelerrs = append(labelerrs, "Invalid label value - label=["+label+"%], labelvalue=["+labelvalue+"]")
\r
260 func IsValidNumber(value, min, max int) []string {
\r
264 errs = append(errs, "invalid constraints")
\r
269 errs = append(errs, "value less than minimum")
\r
272 errs = append(errs, "value greater than maximum")
\r
277 func IsValidNumberStr(value string, min, max int) []string {
\r
281 errs = append(errs, "invalid constraints")
\r
285 n, err := strconv.Atoi(value)
\r
287 errs = append(errs, err.Error())
\r
291 errs = append(errs, "value less than minimum")
\r
294 errs = append(errs, "value greater than maximum")
\r
300 IsValidParameterPresent method takes in a vars map and a array of string parameters
\r
301 that you expect to be present in the GET request.
\r
302 Returns Nil if all the parameters are present or else shall return error message.
\r
304 func IsValidParameterPresent(vars map[string]string, sp []string) error {
\r
306 for i := range sp {
\r
309 errMessage := fmt.Sprintf("Missing %v in GET request", sp[i])
\r
310 return fmt.Errorf(errMessage)
\r
318 // ValidateJsonSchemaData function validates the document against the Json Schema
\r
319 func ValidateJsonSchemaData(jsonSchemaFile string, jsonData interface{}) (error, int) {
\r
321 // Read the Json Schema File
\r
322 if _, err := os.Stat(jsonSchemaFile); err != nil {
\r
323 if os.IsNotExist(err) {
\r
324 err = pkgerrors.New("JsonSchemaValidation: File " + jsonSchemaFile + " not found")
\r
326 err = pkgerrors.Wrap(err, "JsonSchemaValidation: Stat file error")
\r
328 return err, http.StatusInternalServerError
\r
330 rawBytes, err := ioutil.ReadFile(jsonSchemaFile)
\r
332 return pkgerrors.Wrap(err, "JsonSchemaValidation: Read JSON file error"), http.StatusInternalServerError
\r
335 // Json encode the data
\r
336 req, err := json.Marshal(jsonData)
\r
338 return pkgerrors.Wrap(err, "JsonSchemaValidation, Request Body error"), http.StatusBadRequest
\r
341 // Load schema and document
\r
342 schemaLoader := gojsonschema.NewStringLoader(string(rawBytes))
\r
343 s, err := gojsonschema.NewSchema(schemaLoader)
\r
345 return pkgerrors.Wrap(err, "JsonSchemaValidation: Validation error"), http.StatusInternalServerError
\r
347 documentLoader := gojsonschema.NewStringLoader(string(req))
\r
348 result, err := s.Validate(documentLoader)
\r
350 return pkgerrors.Wrap(err, "JsonSchemaValidation: Validation error"), http.StatusInternalServerError
\r
352 // Validate document against Json Schema
\r
353 if !result.Valid() {
\r
354 for _, desc := range result.Errors() {
\r
355 log.Error("The document is not valid", log.Fields{
\r
356 "Error": desc.Description(),
\r
359 return pkgerrors.New("JsonSchemaValidation: Document Validation failed"), http.StatusBadRequest
\r