Skip to content

Commit fc4a8c2

Browse files
authored
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
1 parent d475d53 commit fc4a8c2

File tree

7 files changed

+61
-22
lines changed

7 files changed

+61
-22
lines changed

custom/conf/app.example.ini

+2
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,8 @@ REGISTER_MANUAL_CONFIRM = false
617617
; List of domain names that are allowed to be used to register on a Gitea instance
618618
; gitea.io,example.com
619619
EMAIL_DOMAIN_WHITELIST =
620+
; Comma-separated list of domain names that are not allowed to be used to register on a Gitea instance
621+
EMAIL_DOMAIN_BLOCKLIST =
620622
; Disallow registration, only allow admins to create accounts.
621623
DISABLE_REGISTRATION = false
622624
; Allow registration only using third-party services, it works only when DISABLE_REGISTRATION is false

docs/content/doc/advanced/config-cheat-sheet.en-us.md

+1
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ relation to port exhaustion.
466466
- `DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME`: **true**: Only allow users with write permissions to track time.
467467
- `EMAIL_DOMAIN_WHITELIST`: **\<empty\>**: If non-empty, list of domain names that can only be used to register
468468
on this instance.
469+
- `EMAIL_DOMAIN_BLOCKLIST`: **\<empty\>**: If non-empty, list of domain names that cannot be used to register on this instance
469470
- `SHOW_REGISTRATION_BUTTON`: **! DISABLE\_REGISTRATION**: Show Registration Button
470471
- `SHOW_MILESTONES_DASHBOARD_PAGE`: **true** Enable this to show the milestones dashboard page - a view of all the user's milestones
471472
- `AUTO_WATCH_NEW_REPOS`: **true**: Enable this to let all organisation users watch new repos when they are created

docs/content/doc/help/faq.en-us.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,14 @@ For more information, refer to Gitea's [API docs]({{< relref "doc/developers/api
120120

121121
There are multiple things you can combine to prevent spammers.
122122

123-
1. By only whitelisting certain domains with OpenID (see below)
124-
2. Setting `ENABLE_CAPTCHA` to `true` in your `app.ini` and properly configuring `RECAPTCHA_SECRET` and `RECAPTCHA_SITEKEY`
125-
3. Settings `DISABLE_REGISTRATION` to `true` and creating new users via the [CLI]({{< relref "doc/usage/command-line.en-us.md" >}}), [API]({{< relref "doc/developers/api-usage.en-us.md" >}}), or Gitea's Admin UI
123+
1. By whitelisting or blocklisting certain email domains
124+
2. By only whitelisting certain domains with OpenID (see below)
125+
3. Setting `ENABLE_CAPTCHA` to `true` in your `app.ini` and properly configuring `RECAPTCHA_SECRET` and `RECAPTCHA_SITEKEY`
126+
4. Settings `DISABLE_REGISTRATION` to `true` and creating new users via the [CLI]({{< relref "doc/usage/command-line.en-us.md" >}}), [API]({{< relref "doc/developers/api-usage.en-us.md" >}}), or Gitea's Admin UI
126127

127-
### Only allow certain email domains
128+
### Only allow/block certain email domains
128129

129-
You can configure `EMAIL_DOMAIN_WHITELIST` in your app.ini under `[service]`
130+
You can configure `EMAIL_DOMAIN_WHITELIST` or `EMAIL_DOMAIN_BLOCKLIST` in your app.ini under `[service]`
130131

131132
### Only allow/block certain OpenID providers
132133

modules/forms/user_form.go

+21-10
Original file line numberDiff line numberDiff line change
@@ -95,23 +95,21 @@ func (f *RegisterForm) Validate(req *http.Request, errs binding.Errors) binding.
9595
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
9696
}
9797

98-
// IsEmailDomainWhitelisted validates that the email address
99-
// provided by the user matches what has been configured .
100-
// If the domain whitelist from the config is empty, it marks the
101-
// email as whitelisted
102-
func (f RegisterForm) IsEmailDomainWhitelisted() bool {
103-
if len(setting.Service.EmailDomainWhitelist) == 0 {
104-
return true
98+
// IsEmailDomainListed checks whether the domain of an email address
99+
// matches a list of domains
100+
func IsEmailDomainListed(list []string, email string) bool {
101+
if len(list) == 0 {
102+
return false
105103
}
106104

107-
n := strings.LastIndex(f.Email, "@")
105+
n := strings.LastIndex(email, "@")
108106
if n <= 0 {
109107
return false
110108
}
111109

112-
domain := strings.ToLower(f.Email[n+1:])
110+
domain := strings.ToLower(email[n+1:])
113111

114-
for _, v := range setting.Service.EmailDomainWhitelist {
112+
for _, v := range list {
115113
if strings.ToLower(v) == domain {
116114
return true
117115
}
@@ -120,6 +118,19 @@ func (f RegisterForm) IsEmailDomainWhitelisted() bool {
120118
return false
121119
}
122120

121+
// IsEmailDomainAllowed validates that the email address
122+
// provided by the user matches what has been configured .
123+
// The email is marked as allowed if it matches any of the
124+
// domains in the whitelist or if it doesn't match any of
125+
// domains in the blocklist, if any such list is not empty.
126+
func (f RegisterForm) IsEmailDomainAllowed() bool {
127+
if len(setting.Service.EmailDomainWhitelist) == 0 {
128+
return !IsEmailDomainListed(setting.Service.EmailDomainBlocklist, f.Email)
129+
}
130+
131+
return IsEmailDomainListed(setting.Service.EmailDomainWhitelist, f.Email)
132+
}
133+
123134
// MustChangePasswordForm form for updating your password after account creation
124135
// by an admin
125136
type MustChangePasswordForm struct {

modules/forms/user_form_test.go

+28-6
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ import (
1212
"github.com/stretchr/testify/assert"
1313
)
1414

15-
func TestRegisterForm_IsDomainWhiteList_Empty(t *testing.T) {
15+
func TestRegisterForm_IsDomainAllowed_Empty(t *testing.T) {
1616
_ = setting.Service
1717

1818
setting.Service.EmailDomainWhitelist = []string{}
1919

2020
form := RegisterForm{}
2121

22-
assert.True(t, form.IsEmailDomainWhitelisted())
22+
assert.True(t, form.IsEmailDomainAllowed())
2323
}
2424

25-
func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) {
25+
func TestRegisterForm_IsDomainAllowed_InvalidEmail(t *testing.T) {
2626
_ = setting.Service
2727

2828
setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
@@ -37,11 +37,11 @@ func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) {
3737
for _, v := range tt {
3838
form := RegisterForm{Email: v.email}
3939

40-
assert.False(t, form.IsEmailDomainWhitelisted())
40+
assert.False(t, form.IsEmailDomainAllowed())
4141
}
4242
}
4343

44-
func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) {
44+
func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) {
4545
_ = setting.Service
4646

4747
setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
@@ -59,6 +59,28 @@ func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) {
5959
for _, v := range tt {
6060
form := RegisterForm{Email: v.email}
6161

62-
assert.Equal(t, v.valid, form.IsEmailDomainWhitelisted())
62+
assert.Equal(t, v.valid, form.IsEmailDomainAllowed())
63+
}
64+
}
65+
66+
func TestRegisterForm_IsDomainAllowed_BlocklistedEmail(t *testing.T) {
67+
_ = setting.Service
68+
69+
setting.Service.EmailDomainWhitelist = []string{}
70+
setting.Service.EmailDomainBlocklist = []string{"gitea.io"}
71+
72+
tt := []struct {
73+
email string
74+
valid bool
75+
}{
76+
{"[email protected]", false},
77+
{"[email protected]", true},
78+
{"hdudhdd", true},
79+
}
80+
81+
for _, v := range tt {
82+
form := RegisterForm{Email: v.email}
83+
84+
assert.Equal(t, v.valid, form.IsEmailDomainAllowed())
6385
}
6486
}

modules/setting/service.go

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var Service struct {
2020
RegisterEmailConfirm bool
2121
RegisterManualConfirm bool
2222
EmailDomainWhitelist []string
23+
EmailDomainBlocklist []string
2324
DisableRegistration bool
2425
AllowOnlyExternalRegistration bool
2526
ShowRegistrationButton bool
@@ -72,6 +73,7 @@ func newService() {
7273
Service.RegisterManualConfirm = false
7374
}
7475
Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(",")
76+
Service.EmailDomainBlocklist = sec.Key("EMAIL_DOMAIN_BLOCKLIST").Strings(",")
7577
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
7678
Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
7779
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()

routers/user/auth.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,7 @@ func SignUpPost(ctx *context.Context) {
11291129
}
11301130
}
11311131

1132-
if !form.IsEmailDomainWhitelisted() {
1132+
if !form.IsEmailDomainAllowed() {
11331133
ctx.RenderWithErr(ctx.Tr("auth.email_domain_blacklisted"), tplSignUp, &form)
11341134
return
11351135
}

0 commit comments

Comments
 (0)