code.gitea.io/gitea@v1.19.3/modules/validation/binding.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package validation
     5  
     6  import (
     7  	"fmt"
     8  	"regexp"
     9  	"strings"
    10  
    11  	"code.gitea.io/gitea/modules/auth"
    12  	"code.gitea.io/gitea/modules/git"
    13  
    14  	"gitea.com/go-chi/binding"
    15  	"github.com/gobwas/glob"
    16  )
    17  
    18  const (
    19  	// ErrGitRefName is git reference name error
    20  	ErrGitRefName = "GitRefNameError"
    21  	// ErrGlobPattern is returned when glob pattern is invalid
    22  	ErrGlobPattern = "GlobPattern"
    23  	// ErrRegexPattern is returned when a regex pattern is invalid
    24  	ErrRegexPattern = "RegexPattern"
    25  	// ErrUsername is username error
    26  	ErrUsername = "UsernameError"
    27  	// ErrInvalidGroupTeamMap is returned when a group team mapping is invalid
    28  	ErrInvalidGroupTeamMap = "InvalidGroupTeamMap"
    29  )
    30  
    31  // AddBindingRules adds additional binding rules
    32  func AddBindingRules() {
    33  	addGitRefNameBindingRule()
    34  	addValidURLBindingRule()
    35  	addValidSiteURLBindingRule()
    36  	addGlobPatternRule()
    37  	addRegexPatternRule()
    38  	addGlobOrRegexPatternRule()
    39  	addUsernamePatternRule()
    40  	addValidGroupTeamMapRule()
    41  }
    42  
    43  func addGitRefNameBindingRule() {
    44  	// Git refname validation rule
    45  	binding.AddRule(&binding.Rule{
    46  		IsMatch: func(rule string) bool {
    47  			return strings.HasPrefix(rule, "GitRefName")
    48  		},
    49  		IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
    50  			str := fmt.Sprintf("%v", val)
    51  
    52  			if !git.IsValidRefPattern(str) {
    53  				errs.Add([]string{name}, ErrGitRefName, "GitRefName")
    54  				return false, errs
    55  			}
    56  			return true, errs
    57  		},
    58  	})
    59  }
    60  
    61  func addValidURLBindingRule() {
    62  	// URL validation rule
    63  	binding.AddRule(&binding.Rule{
    64  		IsMatch: func(rule string) bool {
    65  			return strings.HasPrefix(rule, "ValidUrl")
    66  		},
    67  		IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
    68  			str := fmt.Sprintf("%v", val)
    69  			if len(str) != 0 && !IsValidURL(str) {
    70  				errs.Add([]string{name}, binding.ERR_URL, "Url")
    71  				return false, errs
    72  			}
    73  
    74  			return true, errs
    75  		},
    76  	})
    77  }
    78  
    79  func addValidSiteURLBindingRule() {
    80  	// URL validation rule
    81  	binding.AddRule(&binding.Rule{
    82  		IsMatch: func(rule string) bool {
    83  			return strings.HasPrefix(rule, "ValidSiteUrl")
    84  		},
    85  		IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
    86  			str := fmt.Sprintf("%v", val)
    87  			if len(str) != 0 && !IsValidSiteURL(str) {
    88  				errs.Add([]string{name}, binding.ERR_URL, "Url")
    89  				return false, errs
    90  			}
    91  
    92  			return true, errs
    93  		},
    94  	})
    95  }
    96  
    97  func addGlobPatternRule() {
    98  	binding.AddRule(&binding.Rule{
    99  		IsMatch: func(rule string) bool {
   100  			return rule == "GlobPattern"
   101  		},
   102  		IsValid: globPatternValidator,
   103  	})
   104  }
   105  
   106  func globPatternValidator(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
   107  	str := fmt.Sprintf("%v", val)
   108  
   109  	if len(str) != 0 {
   110  		if _, err := glob.Compile(str); err != nil {
   111  			errs.Add([]string{name}, ErrGlobPattern, err.Error())
   112  			return false, errs
   113  		}
   114  	}
   115  
   116  	return true, errs
   117  }
   118  
   119  func addRegexPatternRule() {
   120  	binding.AddRule(&binding.Rule{
   121  		IsMatch: func(rule string) bool {
   122  			return rule == "RegexPattern"
   123  		},
   124  		IsValid: regexPatternValidator,
   125  	})
   126  }
   127  
   128  func regexPatternValidator(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
   129  	str := fmt.Sprintf("%v", val)
   130  
   131  	if _, err := regexp.Compile(str); err != nil {
   132  		errs.Add([]string{name}, ErrRegexPattern, err.Error())
   133  		return false, errs
   134  	}
   135  
   136  	return true, errs
   137  }
   138  
   139  func addGlobOrRegexPatternRule() {
   140  	binding.AddRule(&binding.Rule{
   141  		IsMatch: func(rule string) bool {
   142  			return rule == "GlobOrRegexPattern"
   143  		},
   144  		IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
   145  			str := strings.TrimSpace(fmt.Sprintf("%v", val))
   146  
   147  			if len(str) >= 2 && strings.HasPrefix(str, "/") && strings.HasSuffix(str, "/") {
   148  				return regexPatternValidator(errs, name, str[1:len(str)-1])
   149  			}
   150  			return globPatternValidator(errs, name, val)
   151  		},
   152  	})
   153  }
   154  
   155  func addUsernamePatternRule() {
   156  	binding.AddRule(&binding.Rule{
   157  		IsMatch: func(rule string) bool {
   158  			return rule == "Username"
   159  		},
   160  		IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
   161  			str := fmt.Sprintf("%v", val)
   162  			if !IsValidUsername(str) {
   163  				errs.Add([]string{name}, ErrUsername, "invalid username")
   164  				return false, errs
   165  			}
   166  			return true, errs
   167  		},
   168  	})
   169  }
   170  
   171  func addValidGroupTeamMapRule() {
   172  	binding.AddRule(&binding.Rule{
   173  		IsMatch: func(rule string) bool {
   174  			return strings.HasPrefix(rule, "ValidGroupTeamMap")
   175  		},
   176  		IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
   177  			_, err := auth.UnmarshalGroupTeamMapping(fmt.Sprintf("%v", val))
   178  			if err != nil {
   179  				errs.Add([]string{name}, ErrInvalidGroupTeamMap, err.Error())
   180  				return false, errs
   181  			}
   182  
   183  			return true, errs
   184  		},
   185  	})
   186  }
   187  
   188  func portOnly(hostport string) string {
   189  	colon := strings.IndexByte(hostport, ':')
   190  	if colon == -1 {
   191  		return ""
   192  	}
   193  	if i := strings.Index(hostport, "]:"); i != -1 {
   194  		return hostport[i+len("]:"):]
   195  	}
   196  	if strings.Contains(hostport, "]") {
   197  		return ""
   198  	}
   199  	return hostport[colon+len(":"):]
   200  }
   201  
   202  func validPort(p string) bool {
   203  	for _, r := range []byte(p) {
   204  		if r < '0' || r > '9' {
   205  			return false
   206  		}
   207  	}
   208  	return true
   209  }