summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2023-05-22 08:05:44 +0800
committerGitHub <noreply@github.com>2023-05-22 00:05:44 +0000
commit2cb66fff60c95efbd58b797f1197f2421f4687ce (patch)
tree31f92c081c0bea16089a834c80c5797d8c78c1ac
parent19993d8814e227ac0a52b73d36fdb03fbb143c3f (diff)
downloadgitea-2cb66fff60c95efbd58b797f1197f2421f4687ce.tar.gz
gitea-2cb66fff60c95efbd58b797f1197f2421f4687ce.zip
Support wildcard in email domain allow/block list (#24831)
Replace #20257 (which is stale and incomplete) Close #20255 Major changes: * Deprecate the "WHITELIST", use "ALLOWLIST" * Add wildcard support for EMAIL_DOMAIN_ALLOWLIST/EMAIL_DOMAIN_BLOCKLIST * Update example config file and document * Improve tests
-rw-r--r--custom/conf/app.example.ini8
-rw-r--r--docs/content/doc/administration/config-cheat-sheet.en-us.md5
-rw-r--r--modules/setting/service.go27
-rw-r--r--modules/setting/service_test.go46
-rw-r--r--services/forms/user_form.go17
-rw-r--r--services/forms/user_form_test.go49
6 files changed, 118 insertions, 34 deletions
diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index 27e56542ee..3ee2270d33 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -700,11 +700,11 @@ LEVEL = Info
;; Whether a new user needs to be confirmed manually after registration. (Requires `REGISTER_EMAIL_CONFIRM` to be disabled.)
;REGISTER_MANUAL_CONFIRM = false
;;
-;; List of domain names that are allowed to be used to register on a Gitea instance
-;; gitea.io,example.com
-;EMAIL_DOMAIN_WHITELIST =
+;; List of domain names that are allowed to be used to register on a Gitea instance, wildcard is supported
+;; eg: gitea.io,example.com,*.mydomain.com
+;EMAIL_DOMAIN_ALLOWLIST =
;;
-;; Comma-separated list of domain names that are not allowed to be used to register on a Gitea instance
+;; Comma-separated list of domain names that are not allowed to be used to register on a Gitea instance, wildcard is supported
;EMAIL_DOMAIN_BLOCKLIST =
;;
;; Disallow registration, only allow admins to create accounts.
diff --git a/docs/content/doc/administration/config-cheat-sheet.en-us.md b/docs/content/doc/administration/config-cheat-sheet.en-us.md
index 5fa4c5624c..cb75fc588a 100644
--- a/docs/content/doc/administration/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/administration/config-cheat-sheet.en-us.md
@@ -651,9 +651,8 @@ And the following unique queues:
- `ENABLE_TIMETRACKING`: **true**: Enable Timetracking feature.
- `DEFAULT_ENABLE_TIMETRACKING`: **true**: Allow repositories to use timetracking by default.
- `DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME`: **true**: Only allow users with write permissions to track time.
-- `EMAIL_DOMAIN_WHITELIST`: **\<empty\>**: If non-empty, list of domain names that can only be used to register
- on this instance.
-- `EMAIL_DOMAIN_BLOCKLIST`: **\<empty\>**: If non-empty, list of domain names that cannot be used to register on this instance
+- `EMAIL_DOMAIN_ALLOWLIST`: **\<empty\>**: If non-empty, comma separated list of domain names that can only be used to register on this instance, wildcard is supported.
+- `EMAIL_DOMAIN_BLOCKLIST`: **\<empty\>**: If non-empty, comma separated list of domain names that cannot be used to register on this instance, wildcard is supported.
- `SHOW_REGISTRATION_BUTTON`: **! DISABLE\_REGISTRATION**: Show Registration Button
- `SHOW_MILESTONES_DASHBOARD_PAGE`: **true** Enable this to show the milestones dashboard page - a view of all the user's milestones
- `AUTO_WATCH_NEW_REPOS`: **true**: Enable this to let all organisation users watch new repos when they are created
diff --git a/modules/setting/service.go b/modules/setting/service.go
index d4a31ba5d4..03225f566b 100644
--- a/modules/setting/service.go
+++ b/modules/setting/service.go
@@ -10,6 +10,8 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/structs"
+
+ "github.com/gobwas/glob"
)
// enumerates all the types of captchas
@@ -33,8 +35,8 @@ var Service = struct {
ResetPwdCodeLives int
RegisterEmailConfirm bool
RegisterManualConfirm bool
- EmailDomainWhitelist []string
- EmailDomainBlocklist []string
+ EmailDomainAllowList []glob.Glob
+ EmailDomainBlockList []glob.Glob
DisableRegistration bool
AllowOnlyInternalRegistration bool
AllowOnlyExternalRegistration bool
@@ -114,6 +116,20 @@ func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) {
return result
}
+func CompileEmailGlobList(sec ConfigSection, keys ...string) (globs []glob.Glob) {
+ for _, key := range keys {
+ list := sec.Key(key).Strings(",")
+ for _, s := range list {
+ if g, err := glob.Compile(s); err == nil {
+ globs = append(globs, g)
+ } else {
+ log.Error("Skip invalid email allow/block list expression %q: %v", s, err)
+ }
+ }
+ }
+ return globs
+}
+
func loadServiceFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("service")
Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
@@ -130,8 +146,11 @@ func loadServiceFrom(rootCfg ConfigProvider) {
} else {
Service.RegisterManualConfirm = false
}
- Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(",")
- Service.EmailDomainBlocklist = sec.Key("EMAIL_DOMAIN_BLOCKLIST").Strings(",")
+ if sec.HasKey("EMAIL_DOMAIN_WHITELIST") {
+ deprecatedSetting(rootCfg, "service", "EMAIL_DOMAIN_WHITELIST", "service", "EMAIL_DOMAIN_ALLOWLIST", "1.21")
+ }
+ Service.EmailDomainAllowList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_WHITELIST", "EMAIL_DOMAIN_ALLOWLIST")
+ Service.EmailDomainBlockList = CompileEmailGlobList(sec, "EMAIL_DOMAIN_BLOCKLIST")
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
diff --git a/modules/setting/service_test.go b/modules/setting/service_test.go
new file mode 100644
index 0000000000..656e759f42
--- /dev/null
+++ b/modules/setting/service_test.go
@@ -0,0 +1,46 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "testing"
+
+ "github.com/gobwas/glob"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLoadServices(t *testing.T) {
+ oldService := Service
+ defer func() {
+ Service = oldService
+ }()
+
+ cfg, err := NewConfigProviderFromData(`
+[service]
+EMAIL_DOMAIN_WHITELIST = d1, *.w
+EMAIL_DOMAIN_ALLOWLIST = d2, *.a
+EMAIL_DOMAIN_BLOCKLIST = d3, *.b
+`)
+ assert.NoError(t, err)
+ loadServiceFrom(cfg)
+
+ match := func(globs []glob.Glob, s string) bool {
+ for _, g := range globs {
+ if g.Match(s) {
+ return true
+ }
+ }
+ return false
+ }
+
+ assert.True(t, match(Service.EmailDomainAllowList, "d1"))
+ assert.True(t, match(Service.EmailDomainAllowList, "foo.w"))
+ assert.True(t, match(Service.EmailDomainAllowList, "d2"))
+ assert.True(t, match(Service.EmailDomainAllowList, "foo.a"))
+ assert.False(t, match(Service.EmailDomainAllowList, "d3"))
+
+ assert.True(t, match(Service.EmailDomainBlockList, "d3"))
+ assert.True(t, match(Service.EmailDomainBlockList, "foo.b"))
+ assert.False(t, match(Service.EmailDomainBlockList, "d1"))
+}
diff --git a/services/forms/user_form.go b/services/forms/user_form.go
index fa8129bf85..1e04f85319 100644
--- a/services/forms/user_form.go
+++ b/services/forms/user_form.go
@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/web/middleware"
"gitea.com/go-chi/binding"
+ "github.com/gobwas/glob"
)
// InstallForm form for installation page
@@ -105,8 +106,8 @@ func (f *RegisterForm) Validate(req *http.Request, errs binding.Errors) binding.
// IsEmailDomainListed checks whether the domain of an email address
// matches a list of domains
-func IsEmailDomainListed(list []string, email string) bool {
- if len(list) == 0 {
+func IsEmailDomainListed(globs []glob.Glob, email string) bool {
+ if len(globs) == 0 {
return false
}
@@ -117,8 +118,8 @@ func IsEmailDomainListed(list []string, email string) bool {
domain := strings.ToLower(email[n+1:])
- for _, v := range list {
- if strings.ToLower(v) == domain {
+ for _, g := range globs {
+ if g.Match(domain) {
return true
}
}
@@ -131,12 +132,12 @@ func IsEmailDomainListed(list []string, email string) bool {
// The email is marked as allowed if it matches any of the
// domains in the whitelist or if it doesn't match any of
// domains in the blocklist, if any such list is not empty.
-func (f RegisterForm) IsEmailDomainAllowed() bool {
- if len(setting.Service.EmailDomainWhitelist) == 0 {
- return !IsEmailDomainListed(setting.Service.EmailDomainBlocklist, f.Email)
+func (f *RegisterForm) IsEmailDomainAllowed() bool {
+ if len(setting.Service.EmailDomainAllowList) == 0 {
+ return !IsEmailDomainListed(setting.Service.EmailDomainBlockList, f.Email)
}
- return IsEmailDomainListed(setting.Service.EmailDomainWhitelist, f.Email)
+ return IsEmailDomainListed(setting.Service.EmailDomainAllowList, f.Email)
}
// MustChangePasswordForm form for updating your password after account creation
diff --git a/services/forms/user_form_test.go b/services/forms/user_form_test.go
index 225686f0fe..84efa25d53 100644
--- a/services/forms/user_form_test.go
+++ b/services/forms/user_form_test.go
@@ -10,13 +10,17 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/modules/setting"
+ "github.com/gobwas/glob"
"github.com/stretchr/testify/assert"
)
func TestRegisterForm_IsDomainAllowed_Empty(t *testing.T) {
- _ = setting.Service
+ oldService := setting.Service
+ defer func() {
+ setting.Service = oldService
+ }()
- setting.Service.EmailDomainWhitelist = []string{}
+ setting.Service.EmailDomainAllowList = nil
form := RegisterForm{}
@@ -24,15 +28,18 @@ func TestRegisterForm_IsDomainAllowed_Empty(t *testing.T) {
}
func TestRegisterForm_IsDomainAllowed_InvalidEmail(t *testing.T) {
- _ = setting.Service
+ oldService := setting.Service
+ defer func() {
+ setting.Service = oldService
+ }()
- setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
+ setting.Service.EmailDomainAllowList = []glob.Glob{glob.MustCompile("gitea.io")}
tt := []struct {
email string
}{
- {"securitygieqqq"},
- {"hdudhdd"},
+ {"invalid-email"},
+ {"gitea.io"},
}
for _, v := range tt {
@@ -42,10 +49,13 @@ func TestRegisterForm_IsDomainAllowed_InvalidEmail(t *testing.T) {
}
}
-func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) {
- _ = setting.Service
+func TestRegisterForm_IsDomainAllowed_AllowedEmail(t *testing.T) {
+ oldService := setting.Service
+ defer func() {
+ setting.Service = oldService
+ }()
- setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
+ setting.Service.EmailDomainAllowList = []glob.Glob{glob.MustCompile("gitea.io"), glob.MustCompile("*.allow")}
tt := []struct {
email string
@@ -53,8 +63,11 @@ func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) {
}{
{"security@gitea.io", true},
{"security@gITea.io", true},
- {"hdudhdd", false},
+ {"invalid", false},
{"seee@example.com", false},
+
+ {"user@my.allow", true},
+ {"user@my.allow1", false},
}
for _, v := range tt {
@@ -64,11 +77,14 @@ func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) {
}
}
-func TestRegisterForm_IsDomainAllowed_BlocklistedEmail(t *testing.T) {
- _ = setting.Service
+func TestRegisterForm_IsDomainAllowed_BlockedEmail(t *testing.T) {
+ oldService := setting.Service
+ defer func() {
+ setting.Service = oldService
+ }()
- setting.Service.EmailDomainWhitelist = []string{}
- setting.Service.EmailDomainBlocklist = []string{"gitea.io"}
+ setting.Service.EmailDomainAllowList = nil
+ setting.Service.EmailDomainBlockList = []glob.Glob{glob.MustCompile("gitea.io"), glob.MustCompile("*.block")}
tt := []struct {
email string
@@ -76,7 +92,10 @@ func TestRegisterForm_IsDomainAllowed_BlocklistedEmail(t *testing.T) {
}{
{"security@gitea.io", false},
{"security@gitea.example", true},
- {"hdudhdd", true},
+ {"invalid", true},
+
+ {"user@my.block", false},
+ {"user@my.block1", true},
}
for _, v := range tt {