diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 79bee4208da..15e36dd9d19 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -447,8 +447,11 @@ class UsersController < ApplicationController user ||= User.new user.attributes = new_user_params - # Handle API approval - ReviewableUser.set_approved_fields!(user, current_user) if user.approved? + # Handle API approval and + # auto approve users based on auto_approve_email_domains setting + if user.approved? || EmailValidator.can_auto_approve_user?(user.email) + ReviewableUser.set_approved_fields!(user, current_user) + end # Handle custom fields user_fields = UserField.all diff --git a/app/models/invite_redeemer.rb b/app/models/invite_redeemer.rb index 68a415d274e..172e06f3a71 100644 --- a/app/models/invite_redeemer.rb +++ b/app/models/invite_redeemer.rb @@ -36,7 +36,9 @@ InviteRedeemer = Struct.new(:invite, :username, :name, :password, :user_custom_f registration_ip_address: ip_address } - if !SiteSetting.must_approve_users? || (SiteSetting.must_approve_users? && invite.invited_by.staff?) + if !SiteSetting.must_approve_users? || + (SiteSetting.must_approve_users? && invite.invited_by.staff?) || + EmailValidator.can_auto_approve_user?(user.email) ReviewableUser.set_approved_fields!(user, invite.invited_by) end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index b1fd87890d8..8fa0a360870 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1582,6 +1582,7 @@ en: allow_index_in_robots_txt: "Specify in robots.txt that this site is allowed to be indexed by web search engines. In exceptional cases you can permanently override robots.txt." email_domains_blacklist: "A pipe-delimited list of email domains that users are not allowed to register accounts with. Example: mailinator.com|trashmail.net" email_domains_whitelist: "A pipe-delimited list of email domains that users MUST register accounts with. WARNING: Users with email domains other than those listed will not be allowed!" + auto_approve_email_domains: "Users with email addresses from this list of domains will be automatically approved." hide_email_address_taken: "Don't inform users that an account exists with a given email address during signup and from the forgot password form." log_out_strict: "When logging out, log out ALL sessions for the user on all devices" version_checks: "Ping the Discourse Hub for version updates and show new version messages on the /admin dashboard" diff --git a/config/site_settings.yml b/config/site_settings.yml index 52b7c6002db..33501a4df46 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -459,6 +459,9 @@ login: email_domains_whitelist: default: "" type: list + auto_approve_email_domains: + default: "" + type: list hide_email_address_taken: false log_out_strict: true pending_users_reminder_delay: diff --git a/lib/validators/email_validator.rb b/lib/validators/email_validator.rb index 46d47f8f0df..6436161b827 100644 --- a/lib/validators/email_validator.rb +++ b/lib/validators/email_validator.rb @@ -22,6 +22,14 @@ class EmailValidator < ActiveModel::EachValidator true end + def self.can_auto_approve_user?(email) + if (setting = SiteSetting.auto_approve_email_domains).present? + return !!(EmailValidator.allowed?(email) && email_in_restriction_setting?(setting, email)) + end + + false + end + def self.email_in_restriction_setting?(setting, value) domains = setting.gsub('.', '\.') regexp = Regexp.new("@(.+\\.)?(#{domains})$", true) diff --git a/spec/components/validators/email_validator_spec.rb b/spec/components/validators/email_validator_spec.rb index 0c4616817a5..41c29e1b511 100644 --- a/spec/components/validators/email_validator_spec.rb +++ b/spec/components/validators/email_validator_spec.rb @@ -41,6 +41,23 @@ describe EmailValidator do end end + context "auto approve email domains" do + it "works as expected" do + SiteSetting.auto_approve_email_domains = "example.com" + + expect(EmailValidator.can_auto_approve_user?("foobar@example.com.fr")).to eq(false) + expect(EmailValidator.can_auto_approve_user?("foobar@example.com")).to eq(true) + end + + it "returns false if domain not present in email_domains_whitelist" do + SiteSetting.email_domains_whitelist = "googlemail.com" + SiteSetting.auto_approve_email_domains = "example.com|googlemail.com" + + expect(EmailValidator.can_auto_approve_user?("foobar@example.com")).to eq(false) + expect(EmailValidator.can_auto_approve_user?("foobar@googlemail.com")).to eq(true) + end + end + context '.email_regex' do it 'should match valid emails' do expect(!!('test@discourse.org' =~ EmailValidator.email_regex)).to eq(true) diff --git a/spec/models/invite_redeemer_spec.rb b/spec/models/invite_redeemer_spec.rb index 6098adddcdf..814fe42124e 100644 --- a/spec/models/invite_redeemer_spec.rb +++ b/spec/models/invite_redeemer_spec.rb @@ -59,7 +59,7 @@ describe InviteRedeemer do end describe "#redeem" do - fab!(:invite) { Fabricate(:invite) } + fab!(:invite) { Fabricate(:invite, email: "foobar@example.com") } let(:name) { 'john snow' } let(:username) { 'kingofthenorth' } let(:password) { 'know5nOthiNG' } @@ -102,6 +102,16 @@ describe InviteRedeemer do expect(user.approved).to eq(true) end + it "should redeem the invite if invited by non staff and approve if email in auto_approve_email_domains setting" do + SiteSetting.must_approve_users = true + SiteSetting.auto_approve_email_domains = "example.com" + user = invite_redeemer.redeem + + expect(user.name).to eq(name) + expect(user.username).to eq(username) + expect(user.approved).to eq(true) + end + it "should not blow up if invited_by user has been removed" do invite.invited_by.destroy! invite.reload diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 95d675f372b..561eaeb12d9 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -583,7 +583,7 @@ describe UsersController do UsersController.any_instance.stubs(:honeypot_value).returns(nil) UsersController.any_instance.stubs(:challenge_value).returns(nil) SiteSetting.allow_new_registrations = true - @user = Fabricate.build(:user, password: "strongpassword") + @user = Fabricate.build(:user, email: "foobar@example.com", password: "strongpassword") end let(:post_user_params) do @@ -826,6 +826,22 @@ describe UsersController do new_user = User.find(json["user_id"]) expect(new_user.locale).not_to eq("fr") end + + it "will auto approve user if the user email domain matches auto_approve_email_domains setting" do + Jobs.run_immediately! + SiteSetting.must_approve_users = true + SiteSetting.auto_approve_email_domains = "example.com" + + post "/u.json", params: post_user_params.merge(active: true, api_key: api_key.key) + + expect(response.status).to eq(200) + json = JSON.parse(response.body) + + new_user = User.find(json["user_id"]) + expect(json['active']).to be_truthy + expect(new_user.approved).to be_truthy + expect(ReviewableUser.pending.find_by(target: new_user)).to be_blank + end end end