Skip to content

Refactor context flash msg and global variables #33375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions models/db/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"code.gitea.io/gitea/modules/util"
)

var ErrNameEmpty = util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument}

// ErrNameReserved represents a "reserved name" error.
type ErrNameReserved struct {
Name string
Expand Down Expand Up @@ -79,7 +77,7 @@ func (err ErrNameCharsNotAllowed) Unwrap() error {
func IsUsableName(reservedNames, reservedPatterns []string, name string) error {
name = strings.TrimSpace(strings.ToLower(name))
if utf8.RuneCountInString(name) == 0 {
return ErrNameEmpty
return util.SilentWrap{Message: "name is empty", Err: util.ErrInvalidArgument}
}

for i := range reservedNames {
Expand Down
27 changes: 19 additions & 8 deletions models/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"regexp"
"strconv"
"strings"
"sync"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
Expand Down Expand Up @@ -61,20 +62,30 @@ func (err ErrRepoIsArchived) Error() string {
return fmt.Sprintf("%s is archived", err.Repo.LogString())
}

var (
validRepoNamePattern = regexp.MustCompile(`[-.\w]+`)
invalidRepoNamePattern = regexp.MustCompile(`[.]{2,}`)
reservedRepoNames = []string{".", "..", "-"}
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
)
type globalVarsStruct struct {
validRepoNamePattern *regexp.Regexp
invalidRepoNamePattern *regexp.Regexp
reservedRepoNames []string
reservedRepoPatterns []string
}

var globalVars = sync.OnceValue(func() *globalVarsStruct {
return &globalVarsStruct{
validRepoNamePattern: regexp.MustCompile(`[-.\w]+`),
invalidRepoNamePattern: regexp.MustCompile(`[.]{2,}`),
reservedRepoNames: []string{".", "..", "-"},
reservedRepoPatterns: []string{"*.git", "*.wiki", "*.rss", "*.atom"},
}
})

// IsUsableRepoName returns true when name is usable
func IsUsableRepoName(name string) error {
if !validRepoNamePattern.MatchString(name) || invalidRepoNamePattern.MatchString(name) {
vars := globalVars()
if !vars.validRepoNamePattern.MatchString(name) || vars.invalidRepoNamePattern.MatchString(name) {
// Note: usually this error is normally caught up earlier in the UI
return db.ErrNameCharsNotAllowed{Name: name}
}
return db.IsUsableName(reservedRepoNames, reservedRepoPatterns, name)
return db.IsUsableName(vars.reservedRepoNames, vars.reservedRepoPatterns, name)
}

// TrustModelType defines the types of trust model for this repository
Expand Down
1 change: 1 addition & 0 deletions models/repo/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,5 @@ func TestIsUsableRepoName(t *testing.T) {
assert.Error(t, IsUsableRepoName("the..repo"))
assert.Error(t, IsUsableRepoName("foo.wiki"))
assert.Error(t, IsUsableRepoName("foo.git"))
assert.Error(t, IsUsableRepoName("foo.RSS"))
}
4 changes: 2 additions & 2 deletions models/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ func (u *User) IsMailable() bool {
}

// IsUserExist checks if given username exist,
// the user name should be noncased unique.
// the username should be non-cased unique.
// If uid is presented, then check will rule out that one,
// it is used when update a username in settings page.
func IsUserExist(ctx context.Context, uid int64, name string) (bool, error) {
Expand All @@ -515,7 +515,7 @@ func IsUserExist(ctx context.Context, uid int64, name string) (bool, error) {
Get(&User{LowerName: strings.ToLower(name)})
}

// Note: As of the beginning of 2022, it is recommended to use at least
// SaltByteLength as of the beginning of 2022, it is recommended to use at least
// 64 bits of salt, but NIST is already recommending to use to 128 bits.
// (16 bytes = 16 * 8 = 128 bits)
const SaltByteLength = 16
Expand Down
15 changes: 15 additions & 0 deletions models/user/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ import (
"github.com/stretchr/testify/assert"
)

func TestIsUsableUsername(t *testing.T) {
assert.NoError(t, user_model.IsUsableUsername("a"))
assert.NoError(t, user_model.IsUsableUsername("foo.wiki"))
assert.NoError(t, user_model.IsUsableUsername("foo.git"))

assert.Error(t, user_model.IsUsableUsername("a--b"))
assert.Error(t, user_model.IsUsableUsername("-1_."))
assert.Error(t, user_model.IsUsableUsername(".profile"))
assert.Error(t, user_model.IsUsableUsername("-"))
assert.Error(t, user_model.IsUsableUsername("🌞"))
assert.Error(t, user_model.IsUsableUsername("the..repo"))
assert.Error(t, user_model.IsUsableUsername("foo.RSS"))
assert.Error(t, user_model.IsUsableUsername("foo.PnG"))
}

func TestOAuth2Application_LoadUser(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
app := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: 1})
Expand Down
8 changes: 4 additions & 4 deletions modules/validation/glob_pattern_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ func getGlobPatternErrorString(pattern string) string {
return ""
}

var globValidationTestCases = []validationTestCase{
func Test_GlobPatternValidation(t *testing.T) {
AddBindingRules()

globValidationTestCases := []validationTestCase{
{
description: "Empty glob pattern",
data: TestForm{
Expand Down Expand Up @@ -50,9 +53,6 @@ var globValidationTestCases = []validationTestCase{
},
}

func Test_GlobPatternValidation(t *testing.T) {
AddBindingRules()

for _, testCase := range globValidationTestCases {
t.Run(testCase.description, func(t *testing.T) {
performValidationTest(t, testCase)
Expand Down
27 changes: 18 additions & 9 deletions modules/validation/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,26 @@ import (
"net/url"
"regexp"
"strings"
"sync"

"code.gitea.io/gitea/modules/setting"

"github.com/gobwas/glob"
)

var externalTrackerRegex = regexp.MustCompile(`({?)(?:user|repo|index)+?(}?)`)
type globalVarsStruct struct {
externalTrackerRegex *regexp.Regexp
validUsernamePattern *regexp.Regexp
invalidUsernamePattern *regexp.Regexp
}

var globalVars = sync.OnceValue(func() *globalVarsStruct {
return &globalVarsStruct{
externalTrackerRegex: regexp.MustCompile(`({?)(?:user|repo|index)+?(}?)`),
validUsernamePattern: regexp.MustCompile(`^[\da-zA-Z][-.\w]*$`),
invalidUsernamePattern: regexp.MustCompile(`[-._]{2,}|[-._]$`), // No consecutive or trailing non-alphanumeric chars
}
})

func isLoopbackIP(ip string) bool {
return net.ParseIP(ip).IsLoopback()
Expand Down Expand Up @@ -105,9 +118,9 @@ func IsValidExternalTrackerURLFormat(uri string) bool {
if !IsValidExternalURL(uri) {
return false
}

vars := globalVars()
// check for typoed variables like /{index/ or /[repo}
for _, match := range externalTrackerRegex.FindAllStringSubmatch(uri, -1) {
for _, match := range vars.externalTrackerRegex.FindAllStringSubmatch(uri, -1) {
if (match[1] == "{" || match[2] == "}") && (match[1] != "{" || match[2] != "}") {
return false
}
Expand All @@ -116,14 +129,10 @@ func IsValidExternalTrackerURLFormat(uri string) bool {
return true
}

var (
validUsernamePattern = regexp.MustCompile(`^[\da-zA-Z][-.\w]*$`)
invalidUsernamePattern = regexp.MustCompile(`[-._]{2,}|[-._]$`) // No consecutive or trailing non-alphanumeric chars
)

// IsValidUsername checks if username is valid
func IsValidUsername(name string) bool {
// It is difficult to find a single pattern that is both readable and effective,
// but it's easier to use positive and negative checks.
return validUsernamePattern.MatchString(name) && !invalidUsernamePattern.MatchString(name)
vars := globalVars()
return vars.validUsernamePattern.MatchString(name) && !vars.invalidUsernamePattern.MatchString(name)
}
7 changes: 3 additions & 4 deletions modules/validation/refname_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"gitea.com/go-chi/binding"
)

var gitRefNameValidationTestCases = []validationTestCase{
func Test_GitRefNameValidation(t *testing.T) {
AddBindingRules()
gitRefNameValidationTestCases := []validationTestCase{
{
description: "Reference name contains only characters",
data: TestForm{
Expand Down Expand Up @@ -254,9 +256,6 @@ var gitRefNameValidationTestCases = []validationTestCase{
},
}

func Test_GitRefNameValidation(t *testing.T) {
AddBindingRules()

for _, testCase := range gitRefNameValidationTestCases {
t.Run(testCase.description, func(t *testing.T) {
performValidationTest(t, testCase)
Expand Down
8 changes: 4 additions & 4 deletions modules/validation/regex_pattern_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ func getRegexPatternErrorString(pattern string) string {
return ""
}

var regexValidationTestCases = []validationTestCase{
func Test_RegexPatternValidation(t *testing.T) {
AddBindingRules()

regexValidationTestCases := []validationTestCase{
{
description: "Empty regex pattern",
data: TestForm{
Expand Down Expand Up @@ -48,9 +51,6 @@ var regexValidationTestCases = []validationTestCase{
},
}

func Test_RegexPatternValidation(t *testing.T) {
AddBindingRules()

for _, testCase := range regexValidationTestCases {
t.Run(testCase.description, func(t *testing.T) {
performValidationTest(t, testCase)
Expand Down
8 changes: 4 additions & 4 deletions modules/validation/validurl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import (
"gitea.com/go-chi/binding"
)

var urlValidationTestCases = []validationTestCase{
func Test_ValidURLValidation(t *testing.T) {
AddBindingRules()

urlValidationTestCases := []validationTestCase{
{
description: "Empty URL",
data: TestForm{
Expand Down Expand Up @@ -99,9 +102,6 @@ var urlValidationTestCases = []validationTestCase{
},
}

func Test_ValidURLValidation(t *testing.T) {
AddBindingRules()

for _, testCase := range urlValidationTestCases {
t.Run(testCase.description, func(t *testing.T) {
performValidationTest(t, testCase)
Expand Down
8 changes: 4 additions & 4 deletions modules/validation/validurllist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import (
"gitea.com/go-chi/binding"
)

func Test_ValidURLListValidation(t *testing.T) {
AddBindingRules()

// This is a copy of all the URL tests cases, plus additional ones to
// account for multiple URLs
var urlListValidationTestCases = []validationTestCase{
urlListValidationTestCases := []validationTestCase{
{
description: "Empty URL",
data: TestForm{
Expand Down Expand Up @@ -146,9 +149,6 @@ var urlListValidationTestCases = []validationTestCase{
},
}

func Test_ValidURLListValidation(t *testing.T) {
AddBindingRules()

for _, testCase := range urlListValidationTestCases {
t.Run(testCase.description, func(t *testing.T) {
performValidationTest(t, testCase)
Expand Down
25 changes: 25 additions & 0 deletions modules/web/middleware/flash.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package middleware
import (
"fmt"
"html/template"
"net/http"
"net/url"

"code.gitea.io/gitea/modules/reqctx"
Expand Down Expand Up @@ -65,3 +66,27 @@ func (f *Flash) Success(msg any, current ...bool) {
f.SuccessMsg = flashMsgStringOrHTML(msg)
f.set("success", f.SuccessMsg, current...)
}

func ParseCookieFlashMessage(val string) *Flash {
if vals, _ := url.ParseQuery(val); len(vals) > 0 {
return &Flash{
Values: vals,
ErrorMsg: vals.Get("error"),
SuccessMsg: vals.Get("success"),
InfoMsg: vals.Get("info"),
WarningMsg: vals.Get("warning"),
}
}
return nil
}

func GetSiteCookieFlashMessage(dataStore reqctx.RequestDataStore, req *http.Request, cookieName string) (string, *Flash) {
// Get the last flash message from cookie
lastFlashCookie := GetSiteCookie(req, cookieName)
lastFlashMsg := ParseCookieFlashMessage(lastFlashCookie)
if lastFlashMsg != nil {
lastFlashMsg.DataStore = dataStore
return lastFlashCookie, lastFlashMsg
}
return lastFlashCookie, nil
}
14 changes: 0 additions & 14 deletions modules/web/middleware/request.go

This file was deleted.

8 changes: 4 additions & 4 deletions routers/web/feed/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,18 +258,18 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
}

// GetFeedType return if it is a feed request and altered name and feed type.
func GetFeedType(name string, req *http.Request) (bool, string, string) {
func GetFeedType(name string, req *http.Request) (showFeed bool, feedType string) {
if strings.HasSuffix(name, ".rss") ||
strings.Contains(req.Header.Get("Accept"), "application/rss+xml") {
return true, strings.TrimSuffix(name, ".rss"), "rss"
return true, "rss"
}

if strings.HasSuffix(name, ".atom") ||
strings.Contains(req.Header.Get("Accept"), "application/atom+xml") {
return true, strings.TrimSuffix(name, ".atom"), "atom"
return true, "atom"
}

return false, name, ""
return false, ""
}

// feedActionsToFeedItems convert gitea's Repo's Releases to feeds Item
Expand Down
2 changes: 1 addition & 1 deletion routers/web/feed/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

// RenderBranchFeed render format for branch or file
func RenderBranchFeed(ctx *context.Context) {
_, _, showFeedType := GetFeedType(ctx.PathParam("reponame"), ctx.Req)
_, showFeedType := GetFeedType(ctx.PathParam("reponame"), ctx.Req)
if ctx.Repo.TreePath == "" {
ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType)
} else {
Expand Down
20 changes: 10 additions & 10 deletions routers/web/repo/view_home.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,22 +311,22 @@ func prepareToRenderDirOrFile(entry *git.TreeEntry) func(ctx *context.Context) {
}

func handleRepoHomeFeed(ctx *context.Context) bool {
if setting.Other.EnableFeed {
isFeed, _, showFeedType := feed.GetFeedType(ctx.PathParam("reponame"), ctx.Req)
if isFeed {
switch {
case ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType):
if !setting.Other.EnableFeed {
return false
}
isFeed, showFeedType := feed.GetFeedType(ctx.PathParam("reponame"), ctx.Req)
if !isFeed {
return false
}
if ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType) {
feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType)
case ctx.Repo.TreePath == "":
} else if ctx.Repo.TreePath == "" {
feed.ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType)
case ctx.Repo.TreePath != "":
} else {
feed.ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType)
}
return true
}
}
return false
}

// Home render repository home page
func Home(ctx *context.Context) {
Expand Down
Loading
Loading