snapshot of https://github.com/go-gitea/gitea.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
cache-seeder / prune (push) Has been skipped
cache-seeder / frontend (push) Failing after 3s
cache-seeder / python (push) Failing after 3s
cache-seeder / gobuild (push) Failing after 4s
cache-seeder / lint (bindata, lint-backend) (push) Failing after 3s
giteabot backport / giteabot (push) Has been skipped
giteabot / giteabot (push) Has been skipped
cache-prune / prune (push) Has been skipped
release-nightly-snapcraft / build-and-publish (ubuntu-24.04) (push) Has been cancelled
release-nightly-snapcraft / build-and-publish (ubuntu-24.04-arm) (push) Has been cancelled
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
cron-renovate / cron-renovate (push) Has been skipped
Some checks failed
cache-seeder / prune (push) Has been skipped
cache-seeder / frontend (push) Failing after 3s
cache-seeder / python (push) Failing after 3s
cache-seeder / gobuild (push) Failing after 4s
cache-seeder / lint (bindata, lint-backend) (push) Failing after 3s
giteabot backport / giteabot (push) Has been skipped
giteabot / giteabot (push) Has been skipped
cache-prune / prune (push) Has been skipped
release-nightly-snapcraft / build-and-publish (ubuntu-24.04) (push) Has been cancelled
release-nightly-snapcraft / build-and-publish (ubuntu-24.04-arm) (push) Has been cancelled
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
cron-renovate / cron-renovate (push) Has been skipped
This commit is contained in:
150
modules/validation/binding.go
Normal file
150
modules/validation/binding.go
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gitea.dev/modules/auth"
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/glob"
|
||||
"gitea.dev/modules/json"
|
||||
"gitea.dev/modules/util"
|
||||
|
||||
"gitea.com/go-chi/binding" //nolint:depguard // this package wraps it
|
||||
)
|
||||
|
||||
const (
|
||||
ErrCustomMessage = "CustomMessage"
|
||||
ErrGitRefName = "GitRefNameError"
|
||||
ErrGlobPattern = "GlobPattern"
|
||||
ErrRegexPattern = "RegexPattern"
|
||||
ErrUsername = "UsernameError"
|
||||
ErrInvalidGroupTeamMap = "InvalidGroupTeamMap"
|
||||
ErrInvalidBadgeSlug = "InvalidBadgeSlug"
|
||||
)
|
||||
|
||||
type jsonProvider struct{}
|
||||
|
||||
func (j jsonProvider) Marshal(v any) ([]byte, error) { return json.Marshal(v) }
|
||||
|
||||
func (j jsonProvider) Unmarshal(data []byte, v any) error { return json.Unmarshal(data, v) }
|
||||
|
||||
func (j jsonProvider) NewDecoder(reader io.Reader) binding.JSONDecoder {
|
||||
return json.NewDecoder(reader)
|
||||
}
|
||||
|
||||
func (j jsonProvider) NewEncoder(writer io.Writer) binding.JSONEncoder {
|
||||
return json.NewEncoder(writer)
|
||||
}
|
||||
|
||||
func newFieldError(field reflect.StructField, cls, msg string) *BindingError {
|
||||
return &BindingError{[]string{field.Name}, cls, msg} //nolint:govet // make sure no missing fields
|
||||
}
|
||||
|
||||
// AddBindingRules adds additional binding rules
|
||||
func AddBindingRules(b *binding.Binder) {
|
||||
b.AddRuleNonZero("GitRefName", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
if !git.IsValidRefPattern(f.ValueMustString()) {
|
||||
return newFieldError(f.StructField, ErrGitRefName, "GitRefName")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
b.AddRuleNonZero("ValidUrl", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
if !IsValidURL(f.ValueMustString()) {
|
||||
return newFieldError(f.StructField, binding.ERR_URL, "Url")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
b.AddRuleNonZero("ValidSiteUrl", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
if !IsValidSiteURL(f.ValueMustString()) {
|
||||
return newFieldError(f.StructField, binding.ERR_URL, "Url")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
b.AddRuleNonZero("BadgeSlug", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
if !IsValidBadgeSlug(f.ValueMustString()) {
|
||||
return newFieldError(f.StructField, ErrInvalidBadgeSlug, "invalid badge slug")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
ruleGlobPattern := func(_ context.Context, f *binding.ValidationField) *binding.Error {
|
||||
if _, err := glob.Compile(f.ValueMustString()); err != nil {
|
||||
return newFieldError(f.StructField, ErrGlobPattern, err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
b.AddRuleNonZero("GlobPattern", ruleGlobPattern)
|
||||
ruleRegexPattern := func(_ context.Context, f *binding.ValidationField, val string) *binding.Error {
|
||||
if _, err := regexp.Compile(val); err != nil {
|
||||
return newFieldError(f.StructField, ErrRegexPattern, err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
b.AddRuleNonZero("RegexPattern", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
return ruleRegexPattern(ctx, f, f.ValueMustString())
|
||||
})
|
||||
b.AddRuleNonZero("GlobOrRegexPattern", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
str := f.ValueMustString()
|
||||
if len(str) >= 2 && strings.HasPrefix(str, "/") && strings.HasSuffix(str, "/") {
|
||||
return ruleRegexPattern(ctx, f, str[1:len(str)-1])
|
||||
}
|
||||
return ruleGlobPattern(ctx, f)
|
||||
})
|
||||
|
||||
b.AddRuleNonZero("Username", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
if !IsValidUsername(f.ValueMustString()) {
|
||||
return newFieldError(f.StructField, ErrUsername, "invalid username")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
b.AddRuleNonZero("ValidGroupTeamMap", func(ctx context.Context, f *binding.ValidationField) *binding.Error {
|
||||
_, err := auth.UnmarshalGroupTeamMapping(f.ValueMustString())
|
||||
if err != nil {
|
||||
return newFieldError(f.StructField, ErrInvalidGroupTeamMap, err.Error())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func portOnly(hostport string) string {
|
||||
_, after, ok := strings.Cut(hostport, ":")
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
if _, after2, ok2 := strings.Cut(hostport, "]:"); ok2 {
|
||||
return after2
|
||||
}
|
||||
if strings.Contains(hostport, "]") {
|
||||
return ""
|
||||
}
|
||||
return after
|
||||
}
|
||||
|
||||
func validPort(p string) bool {
|
||||
for _, r := range []byte(p) {
|
||||
if r < '0' || r > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var Binder = sync.OnceValue(func() *binding.Binder {
|
||||
b := binding.NewBinder().WithJSONProvider(jsonProvider{}).WithDefaultRules().WithNameMapper(util.ToSnakeCase)
|
||||
AddBindingRules(b)
|
||||
return b
|
||||
})
|
||||
|
||||
type (
|
||||
BindingErrors = binding.Errors
|
||||
BindingError = binding.Error
|
||||
)
|
||||
Reference in New Issue
Block a user