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