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.

102 lines
2.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. "net/url"
  8. "regexp"
  9. "strings"
  10. "github.com/go-macaron/binding"
  11. )
  12. const (
  13. // ErrGitRefName is git reference name error
  14. ErrGitRefName = "GitRefNameError"
  15. )
  16. var (
  17. // GitRefNamePattern is regular expression wirh unallowed characters in git reference name
  18. GitRefNamePattern = regexp.MustCompile("[^\\d\\w-_\\./]")
  19. )
  20. // AddBindingRules adds additional binding rules
  21. func AddBindingRules() {
  22. addGitRefNameBindingRule()
  23. addValidURLBindingRule()
  24. }
  25. func addGitRefNameBindingRule() {
  26. // Git refname validation rule
  27. binding.AddRule(&binding.Rule{
  28. IsMatch: func(rule string) bool {
  29. return strings.HasPrefix(rule, "GitRefName")
  30. },
  31. IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
  32. str := fmt.Sprintf("%v", val)
  33. if GitRefNamePattern.MatchString(str) {
  34. errs.Add([]string{name}, ErrGitRefName, "GitRefName")
  35. return false, errs
  36. }
  37. // Additional rules as described at https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
  38. if strings.HasPrefix(str, "/") || strings.HasSuffix(str, "/") ||
  39. strings.HasPrefix(str, ".") || strings.HasSuffix(str, ".") ||
  40. strings.HasSuffix(str, ".lock") ||
  41. strings.Contains(str, "..") || strings.Contains(str, "//") {
  42. errs.Add([]string{name}, ErrGitRefName, "GitRefName")
  43. return false, errs
  44. }
  45. return true, errs
  46. },
  47. })
  48. }
  49. func addValidURLBindingRule() {
  50. // URL validation rule
  51. binding.AddRule(&binding.Rule{
  52. IsMatch: func(rule string) bool {
  53. return strings.HasPrefix(rule, "ValidUrl")
  54. },
  55. IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
  56. str := fmt.Sprintf("%v", val)
  57. if len(str) != 0 {
  58. if u, err := url.ParseRequestURI(str); err != nil ||
  59. (u.Scheme != "http" && u.Scheme != "https") ||
  60. !validPort(portOnly(u.Host)) {
  61. errs.Add([]string{name}, binding.ERR_URL, "Url")
  62. return false, errs
  63. }
  64. }
  65. return true, errs
  66. },
  67. })
  68. }
  69. func portOnly(hostport string) string {
  70. colon := strings.IndexByte(hostport, ':')
  71. if colon == -1 {
  72. return ""
  73. }
  74. if i := strings.Index(hostport, "]:"); i != -1 {
  75. return hostport[i+len("]:"):]
  76. }
  77. if strings.Contains(hostport, "]") {
  78. return ""
  79. }
  80. return hostport[colon+len(":"):]
  81. }
  82. func validPort(p string) bool {
  83. for _, r := range []byte(p) {
  84. if r < '0' || r > '9' {
  85. return false
  86. }
  87. }
  88. return true
  89. }