diff options
author | Damien Goutte-Gattat <53821801+gouttegd@users.noreply.github.com> | 2021-02-14 23:31:29 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-15 00:31:29 +0100 |
commit | fc4a8c298031d64d5351898f5e79b35e070cf85f (patch) | |
tree | 802001d7ea87494a03c18e582c7d8000b4c000d2 /modules | |
parent | d475d53c4194ec68a071faf90e33702ead1b3069 (diff) | |
download | gitea-fc4a8c298031d64d5351898f5e79b35e070cf85f.tar.gz gitea-fc4a8c298031d64d5351898f5e79b35e070cf85f.zip |
Allow blocking some email domains from registering an account (#14667)
Gitea allows to whitelist email domains so that only email addresses from certain domains are allowed to register an account, but does not currently allows to do the opposite: blacklisting email domains so that addresses from certain domains are *forbidden* to register an account.
The idea has been briefly mentioned in the discussion about issue #6350, but never implemented. This PR does that.
The rationale is that, in my experience of running a Gitea instance, *a single email domain* is responsible for *most* of the spam accounts, and for *all* of the spam accounts that manage to get past the email confirmation step. So on top of the other spam mitigation measures already available (email confirmation, CAPTCHA, etc.), having the option to block a particularly annoying domain would be helpful.
close #13628
Diffstat (limited to 'modules')
-rw-r--r-- | modules/forms/user_form.go | 31 | ||||
-rw-r--r-- | modules/forms/user_form_test.go | 34 | ||||
-rw-r--r-- | modules/setting/service.go | 2 |
3 files changed, 51 insertions, 16 deletions
diff --git a/modules/forms/user_form.go b/modules/forms/user_form.go index af36628c30..07733baeba 100644 --- a/modules/forms/user_form.go +++ b/modules/forms/user_form.go @@ -95,23 +95,21 @@ func (f *RegisterForm) Validate(req *http.Request, errs binding.Errors) binding. return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// IsEmailDomainWhitelisted validates that the email address -// provided by the user matches what has been configured . -// If the domain whitelist from the config is empty, it marks the -// email as whitelisted -func (f RegisterForm) IsEmailDomainWhitelisted() bool { - if len(setting.Service.EmailDomainWhitelist) == 0 { - return true +// 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 { + return false } - n := strings.LastIndex(f.Email, "@") + n := strings.LastIndex(email, "@") if n <= 0 { return false } - domain := strings.ToLower(f.Email[n+1:]) + domain := strings.ToLower(email[n+1:]) - for _, v := range setting.Service.EmailDomainWhitelist { + for _, v := range list { if strings.ToLower(v) == domain { return true } @@ -120,6 +118,19 @@ func (f RegisterForm) IsEmailDomainWhitelisted() bool { return false } +// IsEmailDomainAllowed validates that the email address +// provided by the user matches what has been configured . +// 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) + } + + return IsEmailDomainListed(setting.Service.EmailDomainWhitelist, f.Email) +} + // MustChangePasswordForm form for updating your password after account creation // by an admin type MustChangePasswordForm struct { diff --git a/modules/forms/user_form_test.go b/modules/forms/user_form_test.go index 6e0518789c..9f67143d12 100644 --- a/modules/forms/user_form_test.go +++ b/modules/forms/user_form_test.go @@ -12,17 +12,17 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRegisterForm_IsDomainWhiteList_Empty(t *testing.T) { +func TestRegisterForm_IsDomainAllowed_Empty(t *testing.T) { _ = setting.Service setting.Service.EmailDomainWhitelist = []string{} form := RegisterForm{} - assert.True(t, form.IsEmailDomainWhitelisted()) + assert.True(t, form.IsEmailDomainAllowed()) } -func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) { +func TestRegisterForm_IsDomainAllowed_InvalidEmail(t *testing.T) { _ = setting.Service setting.Service.EmailDomainWhitelist = []string{"gitea.io"} @@ -37,11 +37,11 @@ func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) { for _, v := range tt { form := RegisterForm{Email: v.email} - assert.False(t, form.IsEmailDomainWhitelisted()) + assert.False(t, form.IsEmailDomainAllowed()) } } -func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) { +func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) { _ = setting.Service setting.Service.EmailDomainWhitelist = []string{"gitea.io"} @@ -59,6 +59,28 @@ func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) { for _, v := range tt { form := RegisterForm{Email: v.email} - assert.Equal(t, v.valid, form.IsEmailDomainWhitelisted()) + assert.Equal(t, v.valid, form.IsEmailDomainAllowed()) + } +} + +func TestRegisterForm_IsDomainAllowed_BlocklistedEmail(t *testing.T) { + _ = setting.Service + + setting.Service.EmailDomainWhitelist = []string{} + setting.Service.EmailDomainBlocklist = []string{"gitea.io"} + + tt := []struct { + email string + valid bool + }{ + {"security@gitea.io", false}, + {"security@gitea.example", true}, + {"hdudhdd", true}, + } + + for _, v := range tt { + form := RegisterForm{Email: v.email} + + assert.Equal(t, v.valid, form.IsEmailDomainAllowed()) } } diff --git a/modules/setting/service.go b/modules/setting/service.go index b6611830be..fc4326fde5 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -20,6 +20,7 @@ var Service struct { RegisterEmailConfirm bool RegisterManualConfirm bool EmailDomainWhitelist []string + EmailDomainBlocklist []string DisableRegistration bool AllowOnlyExternalRegistration bool ShowRegistrationButton bool @@ -72,6 +73,7 @@ func newService() { Service.RegisterManualConfirm = false } Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(",") + Service.EmailDomainBlocklist = sec.Key("EMAIL_DOMAIN_BLOCKLIST").Strings(",") 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() |