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 }