fix: allow free email providers during installation onboarding

Installation onboarding creates the first super-admin via AccountBuilder,
which routes through SignUpEmailValidationService. Without an opt-out, a
self-hoster setting up Chatwoot with a gmail/outlook admin email would
be rejected at install time — a regression for a flow that has nothing
to do with public abuse signals.

Adds an allow_free_email_provider keyword to the service and plumbs it
through AccountBuilder. The public signup paths (api/v1/accounts and
the omniauth callback) continue to enforce the check by default; only
the onboarding controller opts out.
This commit is contained in:
Shivam Mishra
2026-05-19 13:43:01 +05:30
parent 86c8f1ec67
commit 4303dc32fc
5 changed files with 20 additions and 6 deletions
+3 -2
View File
@@ -2,7 +2,8 @@
class AccountBuilder
include CustomExceptions::Account
pattr_initialize [:account_name, :email!, :confirmed, :user, :user_full_name, :user_password, :super_admin, :locale]
pattr_initialize [:account_name, :email!, :confirmed, :user, :user_full_name, :user_password, :super_admin, :locale,
:allow_free_email_provider]
def perform
if @user.nil?
@@ -32,7 +33,7 @@ class AccountBuilder
end
def validate_email
Account::SignUpEmailValidationService.new(@email).perform
Account::SignUpEmailValidationService.new(@email, allow_free_email_provider: @allow_free_email_provider).perform
end
def validate_user
@@ -11,7 +11,8 @@ class Installation::OnboardingController < ApplicationController
email: onboarding_params.dig(:user, :email),
user_password: params.dig(:user, :password),
super_admin: true,
confirmed: true
confirmed: true,
allow_free_email_provider: true
).perform
rescue StandardError => e
redirect_to '/', flash: { error: e.message } and return
@@ -4,8 +4,9 @@ class Account::SignUpEmailValidationService
include CustomExceptions::Account
attr_reader :email
def initialize(email)
def initialize(email, allow_free_email_provider: false)
@email = email
@allow_free_email_provider = allow_free_email_provider
end
def perform
@@ -17,7 +18,7 @@ class Account::SignUpEmailValidationService
raise InvalidEmail.new({ valid: true, disposable: true }) if address.disposable?
raise InvalidEmail.new({ free_email_provider: true }) if address.deny_listed?
raise InvalidEmail.new({ free_email_provider: true }) if !@allow_free_email_provider && address.deny_listed?
true
end
+1 -1
View File
@@ -20,7 +20,7 @@ RSpec.describe AccountBuilder do
# Mock the email validation service
before do
allow(Account::SignUpEmailValidationService).to receive(:new).with(email).and_return(validation_service)
allow(Account::SignUpEmailValidationService).to receive(:new).with(email, allow_free_email_provider: anything).and_return(validation_service)
end
describe '#perform' do
@@ -121,5 +121,16 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do
expect(error.message).to eq(I18n.t('errors.signup.disposable_email'))
end
end
it 'allows free email providers when allow_free_email_provider is true' do
expect(described_class.new('admin@gmail.com', allow_free_email_provider: true).perform).to be(true)
end
it 'still rejects disposable emails even when allow_free_email_provider is true' do
expect { described_class.new('user@mailinator.com', allow_free_email_provider: true).perform }.to raise_error do |error|
expect(error.class.name).to eq('CustomExceptions::Account::InvalidEmail')
expect(error.message).to eq(I18n.t('errors.signup.disposable_email'))
end
end
end
end