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.

141 lines
3.5 KiB

  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package validation
  5. import (
  6. "fmt"
  7. "regexp"
  8. "strings"
  9. "gitea.com/macaron/binding"
  10. "github.com/gobwas/glob"
  11. )
  12. const (
  13. // ErrGitRefName is git reference name error
  14. ErrGitRefName = "GitRefNameError"
  15. // ErrGlobPattern is returned when glob pattern is invalid
  16. ErrGlobPattern = "GlobPattern"
  17. )
  18. var (
  19. // GitRefNamePatternInvalid is regular expression with unallowed characters in git reference name
  20. // They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere.
  21. // They cannot have question-mark ?, asterisk *, or open bracket [ anywhere
  22. GitRefNamePatternInvalid = regexp.MustCompile(`[\000-\037\177 \\~^:?*[]+`)
  23. )
  24. // CheckGitRefAdditionalRulesValid check name is valid on additional rules
  25. func CheckGitRefAdditionalRulesValid(name string) bool {
  26. // Additional rules as described at https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
  27. if strings.HasPrefix(name, "/") || strings.HasSuffix(name, "/") ||
  28. strings.HasSuffix(name, ".") || strings.Contains(name, "..") ||
  29. strings.Contains(name, "//") || strings.Contains(name, "@{") ||
  30. name == "@" {
  31. return false
  32. }
  33. parts := strings.Split(name, "/")
  34. for _, part := range parts {
  35. if strings.HasSuffix(part, ".lock") || strings.HasPrefix(part, ".") {
  36. return false
  37. }
  38. }
  39. return true
  40. }
  41. // AddBindingRules adds additional binding rules
  42. func AddBindingRules() {
  43. addGitRefNameBindingRule()
  44. addValidURLBindingRule()
  45. addGlobPatternRule()
  46. }
  47. func addGitRefNameBindingRule() {
  48. // Git refname validation rule
  49. binding.AddRule(&binding.Rule{
  50. IsMatch: func(rule string) bool {
  51. return strings.HasPrefix(rule, "GitRefName")
  52. },
  53. IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
  54. str := fmt.Sprintf("%v", val)
  55. if GitRefNamePatternInvalid.MatchString(str) {
  56. errs.Add([]string{name}, ErrGitRefName, "GitRefName")
  57. return false, errs
  58. }
  59. if !CheckGitRefAdditionalRulesValid(str) {
  60. errs.Add([]string{name}, ErrGitRefName, "GitRefName")
  61. return false, errs
  62. }
  63. return true, errs
  64. },
  65. })
  66. }
  67. func addValidURLBindingRule() {
  68. // URL validation rule
  69. binding.AddRule(&binding.Rule{
  70. IsMatch: func(rule string) bool {
  71. return strings.HasPrefix(rule, "ValidUrl")
  72. },
  73. IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
  74. str := fmt.Sprintf("%v", val)
  75. if len(str) != 0 && !IsValidURL(str) {
  76. errs.Add([]string{name}, binding.ERR_URL, "Url")
  77. return false, errs
  78. }
  79. return true, errs
  80. },
  81. })
  82. }
  83. func addGlobPatternRule() {
  84. binding.AddRule(&binding.Rule{
  85. IsMatch: func(rule string) bool {
  86. return rule == "GlobPattern"
  87. },
  88. IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
  89. str := fmt.Sprintf("%v", val)
  90. if len(str) != 0 {
  91. if _, err := glob.Compile(str); err != nil {
  92. errs.Add([]string{name}, ErrGlobPattern, err.Error())
  93. return false, errs
  94. }
  95. }
  96. return true, errs
  97. },
  98. })
  99. }
  100. func portOnly(hostport string) string {
  101. colon := strings.IndexByte(hostport, ':')
  102. if colon == -1 {
  103. return ""
  104. }
  105. if i := strings.Index(hostport, "]:"); i != -1 {
  106. return hostport[i+len("]:"):]
  107. }
  108. if strings.Contains(hostport, "]") {
  109. return ""
  110. }
  111. return hostport[colon+len(":"):]
  112. }
  113. func validPort(p string) bool {
  114. for _, r := range []byte(p) {
  115. if r < '0' || r > '9' {
  116. return false
  117. }
  118. }
  119. return true
  120. }