You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

binding.go 5.0KB

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