summaryrefslogtreecommitdiffstats
path: root/modules/validation/binding.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/validation/binding.go')
-rw-r--r--modules/validation/binding.go209
1 files changed, 209 insertions, 0 deletions
diff --git a/modules/validation/binding.go b/modules/validation/binding.go
new file mode 100644
index 00000000..cb0a5063
--- /dev/null
+++ b/modules/validation/binding.go
@@ -0,0 +1,209 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package validation
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+
+ "code.gitea.io/gitea/modules/auth"
+ "code.gitea.io/gitea/modules/git"
+
+ "gitea.com/go-chi/binding"
+ "github.com/gobwas/glob"
+)
+
+const (
+ // ErrGitRefName is git reference name error
+ ErrGitRefName = "GitRefNameError"
+ // ErrGlobPattern is returned when glob pattern is invalid
+ ErrGlobPattern = "GlobPattern"
+ // ErrRegexPattern is returned when a regex pattern is invalid
+ ErrRegexPattern = "RegexPattern"
+ // ErrUsername is username error
+ ErrUsername = "UsernameError"
+ // ErrInvalidGroupTeamMap is returned when a group team mapping is invalid
+ ErrInvalidGroupTeamMap = "InvalidGroupTeamMap"
+)
+
+// AddBindingRules adds additional binding rules
+func AddBindingRules() {
+ addGitRefNameBindingRule()
+ addValidURLBindingRule()
+ addValidSiteURLBindingRule()
+ addGlobPatternRule()
+ addRegexPatternRule()
+ addGlobOrRegexPatternRule()
+ addUsernamePatternRule()
+ addValidGroupTeamMapRule()
+}
+
+func addGitRefNameBindingRule() {
+ // Git refname validation rule
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return strings.HasPrefix(rule, "GitRefName")
+ },
+ IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ str := fmt.Sprintf("%v", val)
+
+ if !git.IsValidRefPattern(str) {
+ errs.Add([]string{name}, ErrGitRefName, "GitRefName")
+ return false, errs
+ }
+ return true, errs
+ },
+ })
+}
+
+func addValidURLBindingRule() {
+ // URL validation rule
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return strings.HasPrefix(rule, "ValidUrl")
+ },
+ IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ str := fmt.Sprintf("%v", val)
+ if len(str) != 0 && !IsValidURL(str) {
+ errs.Add([]string{name}, binding.ERR_URL, "Url")
+ return false, errs
+ }
+
+ return true, errs
+ },
+ })
+}
+
+func addValidSiteURLBindingRule() {
+ // URL validation rule
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return strings.HasPrefix(rule, "ValidSiteUrl")
+ },
+ IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ str := fmt.Sprintf("%v", val)
+ if len(str) != 0 && !IsValidSiteURL(str) {
+ errs.Add([]string{name}, binding.ERR_URL, "Url")
+ return false, errs
+ }
+
+ return true, errs
+ },
+ })
+}
+
+func addGlobPatternRule() {
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return rule == "GlobPattern"
+ },
+ IsValid: globPatternValidator,
+ })
+}
+
+func globPatternValidator(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ str := fmt.Sprintf("%v", val)
+
+ if len(str) != 0 {
+ if _, err := glob.Compile(str); err != nil {
+ errs.Add([]string{name}, ErrGlobPattern, err.Error())
+ return false, errs
+ }
+ }
+
+ return true, errs
+}
+
+func addRegexPatternRule() {
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return rule == "RegexPattern"
+ },
+ IsValid: regexPatternValidator,
+ })
+}
+
+func regexPatternValidator(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ str := fmt.Sprintf("%v", val)
+
+ if _, err := regexp.Compile(str); err != nil {
+ errs.Add([]string{name}, ErrRegexPattern, err.Error())
+ return false, errs
+ }
+
+ return true, errs
+}
+
+func addGlobOrRegexPatternRule() {
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return rule == "GlobOrRegexPattern"
+ },
+ IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ str := strings.TrimSpace(fmt.Sprintf("%v", val))
+
+ if len(str) >= 2 && strings.HasPrefix(str, "/") && strings.HasSuffix(str, "/") {
+ return regexPatternValidator(errs, name, str[1:len(str)-1])
+ }
+ return globPatternValidator(errs, name, val)
+ },
+ })
+}
+
+func addUsernamePatternRule() {
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return rule == "Username"
+ },
+ IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ str := fmt.Sprintf("%v", val)
+ if !IsValidUsername(str) {
+ errs.Add([]string{name}, ErrUsername, "invalid username")
+ return false, errs
+ }
+ return true, errs
+ },
+ })
+}
+
+func addValidGroupTeamMapRule() {
+ binding.AddRule(&binding.Rule{
+ IsMatch: func(rule string) bool {
+ return strings.HasPrefix(rule, "ValidGroupTeamMap")
+ },
+ IsValid: func(errs binding.Errors, name string, val any) (bool, binding.Errors) {
+ _, err := auth.UnmarshalGroupTeamMapping(fmt.Sprintf("%v", val))
+ if err != nil {
+ errs.Add([]string{name}, ErrInvalidGroupTeamMap, err.Error())
+ return false, errs
+ }
+
+ return true, errs
+ },
+ })
+}
+
+func portOnly(hostport string) string {
+ colon := strings.IndexByte(hostport, ':')
+ if colon == -1 {
+ return ""
+ }
+ if i := strings.Index(hostport, "]:"); i != -1 {
+ return hostport[i+len("]:"):]
+ }
+ if strings.Contains(hostport, "]") {
+ return ""
+ }
+ return hostport[colon+len(":"):]
+}
+
+func validPort(p string) bool {
+ for _, r := range []byte(p) {
+ if r < '0' || r > '9' {
+ return false
+ }
+ }
+ return true
+}