feat: update gitea vendor
runner nix smoke / nix label and flake smoke (push) Failing after 1m28s

This commit is contained in:
2026-09-26 21:18:24 +00:00
parent c439c1b948
commit d9b2a4e787
3538 changed files with 116131 additions and 44340 deletions
@@ -8,9 +8,9 @@ import (
"reflect"
"strings"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/validation"
"gitea.dev/modules/translation"
"gitea.dev/modules/util"
"gitea.dev/modules/validation"
"gitea.com/go-chi/binding"
)
@@ -29,7 +29,7 @@ func AssignForm(form any, data map[string]any) {
typ := reflect.TypeOf(form)
val := reflect.ValueOf(form)
for typ.Kind() == reflect.Ptr {
for typ.Kind() == reflect.Pointer {
typ = typ.Elem()
val = val.Elem()
}
@@ -78,82 +78,97 @@ func GetInclude(field reflect.StructField) string {
return getRuleBody(field, "Include(")
}
// Validate validate
func ReportValidationError(errs binding.Errors, data map[string]any, fieldName, classification, errorMsg string) binding.Errors {
errs.Add([]string{fieldName}, classification, errorMsg)
data["HasError"] = true
data["ErrorMsg"] = fieldName + ": " + errorMsg
data["Err_"+fieldName] = true
// there is already a reported validation error, so no need to generate default error messages in Validate()
data["HasErrorFormValidation"] = true
return errs
}
func Validate(errs binding.Errors, data map[string]any, f Form, l translation.Locale) binding.Errors {
if errs.Len() == 0 {
// try to restore the form's values as much as possible,
// especially for RenderWithErrDeprecated to re-render the form with errors
AssignForm(f, data)
if errs.Len() == 0 || data["HasErrorFormValidation"] == true {
return errs
}
// if HasError=true, then must set default error message
// because still a lot of places use `ctx.Data["ErrorMsg"].(string)` even if the error fields can't be found
data["HasError"] = true
// If the field with name errs[0].FieldNames[0] is not found in form
// somehow, some code later on will panic on Data["ErrorMsg"].(string).
// So initialize it to some default.
data["ErrorMsg"] = l.Tr("form.unknown_error")
AssignForm(f, data)
data["ErrorMsg"] = l.TrString("form.unknown_error")
typ := reflect.TypeOf(f)
if typ.Kind() == reflect.Ptr {
if typ.Kind() == reflect.Pointer {
typ = typ.Elem()
}
if field, ok := typ.FieldByName(errs[0].FieldNames[0]); ok {
fieldName := field.Tag.Get("form")
if fieldName != "-" {
data["Err_"+field.Name] = true
trName := field.Tag.Get("locale")
if len(trName) == 0 {
trName = l.TrString("form." + field.Name)
} else {
trName = l.TrString(trName)
}
switch errs[0].Classification {
case binding.ERR_REQUIRED:
data["ErrorMsg"] = trName + l.TrString("form.require_error")
case binding.ERR_ALPHA_DASH:
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_error")
case binding.ERR_ALPHA_DASH_DOT:
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_dot_error")
case validation.ErrGitRefName:
data["ErrorMsg"] = trName + l.TrString("form.git_ref_name_error")
case binding.ERR_SIZE:
data["ErrorMsg"] = trName + l.TrString("form.size_error", GetSize(field))
case binding.ERR_MIN_SIZE:
data["ErrorMsg"] = trName + l.TrString("form.min_size_error", GetMinSize(field))
case binding.ERR_MAX_SIZE:
data["ErrorMsg"] = trName + l.TrString("form.max_size_error", GetMaxSize(field))
case binding.ERR_EMAIL:
data["ErrorMsg"] = trName + l.TrString("form.email_error")
case binding.ERR_URL:
data["ErrorMsg"] = trName + l.TrString("form.url_error", errs[0].Message)
case binding.ERR_INCLUDE:
data["ErrorMsg"] = trName + l.TrString("form.include_error", GetInclude(field))
case validation.ErrGlobPattern:
data["ErrorMsg"] = trName + l.TrString("form.glob_pattern_error", errs[0].Message)
case validation.ErrRegexPattern:
data["ErrorMsg"] = trName + l.TrString("form.regex_pattern_error", errs[0].Message)
case validation.ErrUsername:
data["ErrorMsg"] = trName + l.TrString("form.username_error")
case validation.ErrInvalidGroupTeamMap:
data["ErrorMsg"] = trName + l.TrString("form.invalid_group_team_map_error", errs[0].Message)
case validation.ErrInvalidBadgeSlug:
data["ErrorMsg"] = trName + l.TrString("form.invalid_slug_error")
default:
msg := errs[0].Classification
if msg != "" && errs[0].Message != "" {
msg += ": "
}
msg += errs[0].Message
if msg == "" {
msg = l.TrString("form.unknown_error")
}
data["ErrorMsg"] = trName + ": " + msg
}
return errs
}
field, fieldExists := typ.FieldByName(errs[0].FieldNames[0])
if !fieldExists {
return errs
}
if field.Tag.Get("form") == "-" {
return errs
}
data["Err_"+field.Name] = true
trName := field.Tag.Get("locale")
if len(trName) == 0 {
trName = l.TrString("form." + field.Name)
} else {
trName = l.TrString(trName)
}
switch errs[0].Classification {
case binding.ERR_REQUIRED:
data["ErrorMsg"] = trName + l.TrString("form.require_error")
case binding.ERR_ALPHA_DASH:
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_error")
case binding.ERR_ALPHA_DASH_DOT:
data["ErrorMsg"] = trName + l.TrString("form.alpha_dash_dot_error")
case validation.ErrGitRefName:
data["ErrorMsg"] = trName + l.TrString("form.git_ref_name_error")
case binding.ERR_SIZE:
data["ErrorMsg"] = trName + l.TrString("form.size_error", GetSize(field))
case binding.ERR_MIN_SIZE:
data["ErrorMsg"] = trName + l.TrString("form.min_size_error", GetMinSize(field))
case binding.ERR_MAX_SIZE:
data["ErrorMsg"] = trName + l.TrString("form.max_size_error", GetMaxSize(field))
case binding.ERR_EMAIL:
data["ErrorMsg"] = trName + l.TrString("form.email_error")
case binding.ERR_URL:
data["ErrorMsg"] = trName + l.TrString("form.url_error", errs[0].Message)
case binding.ERR_INCLUDE:
data["ErrorMsg"] = trName + l.TrString("form.include_error", GetInclude(field))
case validation.ErrGlobPattern:
data["ErrorMsg"] = trName + l.TrString("form.glob_pattern_error", errs[0].Message)
case validation.ErrRegexPattern:
data["ErrorMsg"] = trName + l.TrString("form.regex_pattern_error", errs[0].Message)
case validation.ErrUsername:
data["ErrorMsg"] = trName + l.TrString("form.username_error")
case validation.ErrInvalidGroupTeamMap:
data["ErrorMsg"] = trName + l.TrString("form.invalid_group_team_map_error", errs[0].Message)
case validation.ErrInvalidBadgeSlug:
data["ErrorMsg"] = trName + l.TrString("form.invalid_slug_error")
default:
msg := errs[0].Classification
if msg != "" && errs[0].Message != "" {
msg += ": "
}
msg += errs[0].Message
if msg == "" {
msg = l.TrString("form.unknown_error")
}
data["ErrorMsg"] = trName + ": " + msg
}
return errs
}
@@ -9,9 +9,9 @@ import (
"net/url"
"strings"
"code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"gitea.dev/modules/session"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
)
const (
@@ -35,6 +35,11 @@ func DeleteRedirectToCookie(resp http.ResponseWriter) {
}
func RedirectLinkUserLogin(req *http.Request) string {
if req.Header.Get("X-Gitea-Fetch-Action") != "" {
// when building the redirect link for a fetch request, the current link might be a partial page,
// so we only redirect to the login page without redirect_to parameter
return setting.AppSubURL + "/user/login"
}
return setting.AppSubURL + "/user/login?redirect_to=" + url.QueryEscape(setting.AppSubURL+req.URL.RequestURI())
}
@@ -7,9 +7,9 @@ import (
"context"
"time"
"code.gitea.io/gitea/modules/public"
"code.gitea.io/gitea/modules/reqctx"
"code.gitea.io/gitea/modules/setting"
"gitea.dev/modules/public"
"gitea.dev/modules/reqctx"
"gitea.dev/modules/setting"
)
const ContextDataKeySignedUser = "SignedUser"
@@ -9,7 +9,7 @@ import (
"net/http"
"net/url"
"code.gitea.io/gitea/modules/reqctx"
"gitea.dev/modules/reqctx"
)
// Flash represents a one time data transfer between two requests.
@@ -6,12 +6,30 @@ package middleware
import (
"net/http"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/translation/i18n"
"gitea.dev/modules/translation"
"gitea.dev/modules/translation/i18n"
"golang.org/x/text/language"
)
// maxAcceptLanguageLen bounds the Accept-Language header before it reaches
// language.ParseAcceptLanguage. That parser has quadratic-time behavior on long
// malformed inputs, and its built-in guard only counts "-" separators while the
// scanner treats "_" as an alias for "-", so a "_"-heavy header slips past the
// guard and burns CPU. Only the leading (highest-priority) languages are used, so
// truncating a longer header is safe.
const maxAcceptLanguageLen = 200
// parseAcceptLanguage parses the Accept-Language header after bounding its length
// to avoid a quadratic-time DoS on attacker-controlled input.
func parseAcceptLanguage(header string) []language.Tag {
if len(header) > maxAcceptLanguageLen {
header = header[:maxAcceptLanguageLen]
}
tags, _, _ := language.ParseAcceptLanguage(header)
return tags
}
// Locale handle locale
func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale {
// 1. Check URL arguments.
@@ -35,7 +53,7 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale {
// 3. Get language information from 'Accept-Language'.
// The first element in the list is chosen to be the default language automatically.
if len(lang) == 0 {
tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language"))
tags := parseAcceptLanguage(req.Header.Get("Accept-Language"))
tag := translation.Match(tags...)
lang = tag.String()
}
@@ -51,9 +69,3 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale {
func SetLocaleCookie(resp http.ResponseWriter, lang string, maxAge int) {
SetSiteCookie(resp, "lang", lang, maxAge)
}
// DeleteLocaleCookie convenience function to delete the locale cookie consistently
// Setting the lang cookie will trigger the middleware to reset the language to previous state.
func DeleteLocaleCookie(resp http.ResponseWriter) {
SetSiteCookie(resp, "lang", "", -1)
}
@@ -0,0 +1,27 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package middleware
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseAcceptLanguage(t *testing.T) {
// a normal header is parsed and its leading language preserved
tags := parseAcceptLanguage("de-DE,de;q=0.9,en;q=0.8")
assert.NotEmpty(t, tags)
assert.Equal(t, "de-DE", tags[0].String())
// an oversized "_"-separated header would drive ParseAcceptLanguage into its
// quadratic-time path (the built-in guard only counts "-"); the length bound
// keeps the input passed to the parser small so it cannot be used for a DoS.
malicious := strings.Repeat("_aaaaaaaaa", 1<<16) // ~640 KiB, zero "-" characters
assert.Greater(t, len(malicious), maxAcceptLanguageLen)
tags = parseAcceptLanguage(malicious)
// no panic / hang, and nothing meaningful is parsed out of the garbage
assert.Empty(t, tags)
}