diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go index 4ced7c7f3d5..15e2d84b2e9 100644 --- a/models/user/email_address_test.go +++ b/models/user/email_address_test.go @@ -151,16 +151,28 @@ func TestListEmails(t *testing.T) { func TestEmailAddressValidate(t *testing.T) { cases := map[string]bool{ - "": false, - "root@localhost": true, - "user@[192.168.1.2]": true, - "@a": false, - "abc@gmail.com": true, - "abc@gmail.com\n": false, + "": false, + "@a": false, + + // "_" shouldn't appear in domain but can appear in hostname, since we can't stop site admins from doing so, just accept it + "root@local_host": true, + "root@localhost": true, + "root@LOCALHOST": true, + + "user@[192.168.1.2]": true, + "user@[IPv6:FFff::1]": true, + + "abc@gmail.com": true, + "abc@gmail.com.": false, + "abc@gmail.com-": false, + "abc@gmail.com\n": false, + "abc@gmail..com": false, + "abc@gmail com": false, + "abc@gmail*com": false, + "Foo ": false, "abc@gmail.com (x)": false, - "jürgen@example.com": false, - "a@foo_bar.com": false, + "jürgen@example.com": false, // utf8 address is not supported yet } for tc, isValid := range cases { t.Run(tc, func(t *testing.T) { diff --git a/modules/private/manager.go b/modules/private/manager.go index 559de8dc577..58cb72b4163 100644 --- a/modules/private/manager.go +++ b/modules/private/manager.go @@ -38,14 +38,14 @@ func ReloadTemplates(ctx context.Context) ResponseExtra { // FlushOptions represents the options for the flush call type FlushOptions struct { - Timeout time.Duration + Timeout int64 NonBlocking bool } // FlushQueues calls the internal flush-queues function func FlushQueues(ctx context.Context, timeout time.Duration, nonBlocking bool) ResponseExtra { reqURL := setting.LocalURL + "api/internal/manager/flush-queues" - req := newInternalRequestAPI(ctx, reqURL, "POST", FlushOptions{Timeout: timeout, NonBlocking: nonBlocking}) + req := newInternalRequestAPI(ctx, reqURL, "POST", FlushOptions{Timeout: int64(timeout), NonBlocking: nonBlocking}) if timeout > 0 { req.SetReadWriteTimeout(timeout + 10*time.Second) } diff --git a/modules/validation/helpers.go b/modules/validation/helpers.go index 30b8484d0d7..9a4db7014e7 100644 --- a/modules/validation/helpers.go +++ b/modules/validation/helpers.go @@ -14,8 +14,6 @@ import ( "gitea.dev/modules/glob" "gitea.dev/modules/setting" - - "golang.org/x/net/idna" ) type globalVarsStruct struct { @@ -24,6 +22,8 @@ type globalVarsStruct struct { invalidUsernamePattern *regexp.Regexp validBadgeSlugPattern *regexp.Regexp invalidBadgeSlugPattern *regexp.Regexp + validEmailHostName *regexp.Regexp + validEmailHostIP *regexp.Regexp } var globalVars = sync.OnceValue(func() *globalVarsStruct { @@ -33,6 +33,8 @@ var globalVars = sync.OnceValue(func() *globalVarsStruct { invalidUsernamePattern: regexp.MustCompile(`[-._]{2,}|[-._]$`), // No consecutive or trailing non-alphanumeric chars validBadgeSlugPattern: regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]*$`), invalidBadgeSlugPattern: regexp.MustCompile(`[-._]{2,}|[-._]$`), + validEmailHostName: regexp.MustCompile(`^[a-zA-Z0-9][-.\w]*$`), + validEmailHostIP: regexp.MustCompile(`(?i)^\[([0-9.]+|ipv6:[0-9a-f:.]+)\]$`), } }) @@ -124,10 +126,12 @@ func IsEmailAddressValid(email string) bool { return false } _, domain, _ := strings.Cut(email, "@") - if strings.HasPrefix(domain, "[") { - // address like "foo@[192.168.1.2]" - return true + if !globalVars().validEmailHostName.MatchString(domain) && !globalVars().validEmailHostIP.MatchString(domain) { + return false } - _, err = idna.Registration.ToASCII(domain) - return err == nil + if strings.HasPrefix(domain, "-") || strings.HasSuffix(domain, "-") || + strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") { + return false + } + return true } diff --git a/routers/private/manager.go b/routers/private/manager.go index 10f80756be7..28c2debe77c 100644 --- a/routers/private/manager.go +++ b/routers/private/manager.go @@ -5,6 +5,7 @@ package private import ( "net/http" + "time" "gitea.dev/models/db" "gitea.dev/modules/graceful" @@ -34,7 +35,7 @@ func FlushQueues(ctx *context.PrivateContext) { // Save the hammer ctx here - as a new one is created each time you call this. baseCtx := graceful.GetManager().HammerContext() go func() { - err := queue.GetManager().FlushAll(baseCtx, opts.Timeout) + err := queue.GetManager().FlushAll(baseCtx, time.Duration(opts.Timeout)) if err != nil { log.Error("Flushing request timed-out with error: %v", err) } @@ -44,7 +45,7 @@ func FlushQueues(ctx *context.PrivateContext) { }) return } - err := queue.GetManager().FlushAll(ctx, opts.Timeout) + err := queue.GetManager().FlushAll(ctx, time.Duration(opts.Timeout)) if err != nil { ctx.PrivateUserErrorf(http.StatusRequestTimeout, "%v", err) return