Allow Forems to specify which domains are allowed for registration (#11442)
* Allow authors to restrict which emails can sign up * Add form and tests * Check for email presence in allowed email flow * Fix test domains * Fix codeclimate issue
This commit is contained in:
parent
cc63725875
commit
f3a69bbd84
9 changed files with 132 additions and 1 deletions
|
|
@ -123,6 +123,8 @@ module Admin
|
|||
video_encoder_key
|
||||
tag_feed_minimum_score
|
||||
home_feed_minimum_score
|
||||
allowed_registration_email_domains
|
||||
display_email_domain_allow_list_publicly
|
||||
].freeze
|
||||
|
||||
IMAGE_FIELDS =
|
||||
|
|
@ -211,6 +213,7 @@ module Admin
|
|||
errors = []
|
||||
errors << "Brand color must be darker for accessibility." if brand_contrast_too_low
|
||||
errors << "Brand color must be be a 6 character hex (starting with #)." if brand_color_not_hex
|
||||
errors << "Allowed emails must be list of domains." if allowed_domains_include_improper_format
|
||||
redirect_to admin_config_path, alert: "😭 #{errors.to_sentence}" if errors.any?
|
||||
end
|
||||
|
||||
|
|
@ -260,6 +263,16 @@ module Admin
|
|||
hex.present? && !hex.match?(/\A#(\h{6}|\h{3})\z/)
|
||||
end
|
||||
|
||||
def allowed_domains_include_improper_format
|
||||
domains = params.dig(:site_config, :allowed_registration_email_domains)
|
||||
return unless domains
|
||||
|
||||
domains_array = domains.delete(" ").split(",")
|
||||
valid_domains = domains_array
|
||||
.select { |d| d.match?(/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/) }
|
||||
valid_domains.size != domains_array.size
|
||||
end
|
||||
|
||||
def valid_image_url(url)
|
||||
url.match?(VALID_URL)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
resource.registered = true
|
||||
resource.registered_at = Time.current
|
||||
resource.editor_version = "v2"
|
||||
check_allowed_email(resource) if resource.email.present?
|
||||
resource.save if resource.email.present?
|
||||
yield resource if block_given?
|
||||
if resource.persisted?
|
||||
|
|
@ -57,4 +58,13 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
recaptcha_params = { secret_key: SiteConfig.recaptcha_secret_key }
|
||||
params["g-recaptcha-response"] && verify_recaptcha(recaptcha_params)
|
||||
end
|
||||
|
||||
def check_allowed_email(resource)
|
||||
domain = resource.email.split("@").last
|
||||
allow_list = SiteConfig.allowed_registration_email_domains
|
||||
return if allow_list.empty? || allow_list.include?(domain)
|
||||
|
||||
resource.email = nil
|
||||
resource.errors.add(:email, "is not included in allowed domains.")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const emailAuthModalTitle = 'Disable Email address registration';
|
|||
// TODO: Remove the sentence "You must update site config to save this action!"
|
||||
// once we build more robust flow for Admin/Config
|
||||
const emailAuthModalBody =
|
||||
'<p>If you disable Email address as a registration option, people cannot create an account with their email address.</p><p>However, people who have already created an account using their email address can continue to login.</p><p><strong>Please update site config to save this action.</strong></p>';
|
||||
'<p>If you disable Email address as a registration option, people cannot create an account with their email address.</p><p>However, people who have already created an account using their email address can continue to login.</p><p><strong>You must confirm and update site config to save below this action.</strong></p>';
|
||||
|
||||
export default class ConfigController extends Controller {
|
||||
static targets = [
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ module Constants
|
|||
they're creating a new account in your community",
|
||||
placeholder: ""
|
||||
},
|
||||
allowed_registration_email_domains: {
|
||||
description: "Restrict registration to only certain emails? (comma-separated list)",
|
||||
placeholder: "dev.to, forem.com, codenewbie.org"
|
||||
},
|
||||
authentication_providers: {
|
||||
description: "How can users sign in?",
|
||||
placeholder: ""
|
||||
|
|
@ -82,6 +86,9 @@ module Constants
|
|||
default_font: {
|
||||
description: "Determines the default Base Reading Font (registered users can change this in their UX settings)"
|
||||
},
|
||||
display_email_domain_allow_list_publicly: {
|
||||
description: "Do you want to display the list of allowed domains, or keep it private?"
|
||||
},
|
||||
display_jobs_banner: {
|
||||
description: "Display a jobs banner that points users to the jobs page when they type 'job'" \
|
||||
"or 'jobs' in the search box",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ class SiteConfig < RailsSettings::Base
|
|||
# Authentication
|
||||
field :allow_email_password_registration, type: :boolean, default: false
|
||||
field :allow_email_password_login, type: :boolean, default: true
|
||||
field :allowed_registration_email_domains, type: :array, default: %w[]
|
||||
field :display_email_domain_allow_list_publicly, type: :boolean, default: false
|
||||
field :require_captcha_for_email_password_registration, type: :boolean, default: false
|
||||
field :authentication_providers, type: :array, default: proc { Authentication::Providers.available }
|
||||
field :invite_only_mode, type: :boolean, default: false
|
||||
|
|
|
|||
|
|
@ -196,6 +196,24 @@
|
|||
id: "email-registration-checkbox",
|
||||
class: "crayons-checkbox" %>
|
||||
</div>
|
||||
<div class="crayons-field">
|
||||
<%= admin_config_label :allowed_registration_email_domains, "Allowed email domains" %>
|
||||
<%= admin_config_description Constants::SiteConfig::DETAILS[:allowed_registration_email_domains][:description] %>
|
||||
<%= f.text_field :allowed_registration_email_domains,
|
||||
class: "crayons-textfield",
|
||||
value: SiteConfig.allowed_registration_email_domains.join(","),
|
||||
placeholder: Constants::SiteConfig::DETAILS[:allowed_registration_email_domains][:placeholder] %>
|
||||
</div>
|
||||
<div class="crayons-field--checkbox">
|
||||
<%= f.check_box :display_email_domain_allow_list_publicly,
|
||||
checked: SiteConfig.display_email_domain_allow_list_publicly,
|
||||
id: "email-display-emails-publicly-checkbox",
|
||||
class: "crayons-checkbox mt-2" %>
|
||||
<div>
|
||||
<%= admin_config_label :display_email_domain_allow_list_publicly %>
|
||||
<%= admin_config_description Constants::SiteConfig::DETAILS[:display_email_domain_allow_list_publicly][:description] %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="crayons-field--checkbox">
|
||||
<%= f.check_box :require_captcha_for_email_password_registration,
|
||||
checked: SiteConfig.require_captcha_for_email_password_registration,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,23 @@
|
|||
<% else %>
|
||||
<p class="pb-4 fw-bold">Create your account</p>
|
||||
<% end %>
|
||||
<% if SiteConfig.display_email_domain_allow_list_publicly &&
|
||||
SiteConfig.allowed_registration_email_domains.any? %>
|
||||
<div class="crayons-notice crayons-notice--info">
|
||||
<% if SiteConfig.allowed_registration_email_domains.one? %>
|
||||
Registration restricted to <strong>@<%= SiteConfig.allowed_registration_email_domains.first %></strong> emails.
|
||||
<% else %>
|
||||
Registration restricted to the following emails
|
||||
<ul>
|
||||
<% SiteConfig.allowed_registration_email_domains.each do |domain| %>
|
||||
<li>
|
||||
<strong>@<%= domain %></strong></strong>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="crayons-field mt-3">
|
||||
<%= f.label :profile_image, class: "crayons-field__label" %>
|
||||
<%= f.file_field :profile_image, accept: "image/*", class: "crayons-card crayons-card--secondary p-3 flex items-center flex-1 w-100", required: true %>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,26 @@ RSpec.describe "/admin/config", type: :request do
|
|||
expect(SiteConfig.authentication_providers).to eq([provider])
|
||||
end
|
||||
|
||||
it "enables proper domains to allow list" do
|
||||
proper_list = "dev.to, forem.com, forem.dev"
|
||||
post "/admin/config", params: { site_config: { allowed_registration_email_domains: proper_list },
|
||||
confirmation: confirmation_message }
|
||||
expect(SiteConfig.allowed_registration_email_domains).to eq(%w[dev.to forem.com forem.dev])
|
||||
end
|
||||
|
||||
it "does not allow improper domain list" do
|
||||
impproper_list = "dev.to, foremcom, forem.dev"
|
||||
post "/admin/config", params: { site_config: { allowed_registration_email_domains: impproper_list },
|
||||
confirmation: confirmation_message }
|
||||
expect(SiteConfig.allowed_registration_email_domains).not_to eq(%w[dev.to foremcom forem.dev])
|
||||
end
|
||||
|
||||
it "enables display_email_domain_allow_list_publicly" do
|
||||
post "/admin/config", params: { site_config: { display_email_domain_allow_list_publicly: true },
|
||||
confirmation: confirmation_message }
|
||||
expect(SiteConfig.display_email_domain_allow_list_publicly).to be(true)
|
||||
end
|
||||
|
||||
it "enables email authentication" do
|
||||
post "/admin/config", params: { site_config: { allow_email_password_registration: true },
|
||||
confirmation: confirmation_message }
|
||||
|
|
|
|||
|
|
@ -222,6 +222,50 @@ RSpec.describe "Registrations", type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
context "when email registration allowed and email allow list empty" do
|
||||
before do
|
||||
allow(SiteConfig).to receive(:allow_email_password_registration).and_return(true)
|
||||
allow(SiteConfig).to receive(:allowed_registration_email_domains).and_return([])
|
||||
end
|
||||
|
||||
it "creates user when email in allow list" do
|
||||
post "/users", params:
|
||||
{ user: { name: "royal #{rand(10)}",
|
||||
username: "magoo_#{rand(10)}",
|
||||
email: "queenelizabeth@dev.to",
|
||||
password: "PaSSw0rd_yo000",
|
||||
password_confirmation: "PaSSw0rd_yo000" } }
|
||||
expect(User.all.size).to be 1
|
||||
end
|
||||
end
|
||||
|
||||
context "when email registration allowed and email allow list present" do
|
||||
before do
|
||||
allow(SiteConfig).to receive(:allow_email_password_registration).and_return(true)
|
||||
allow(SiteConfig).to receive(:allowed_registration_email_domains).and_return(["dev.to", "forem.com"])
|
||||
end
|
||||
|
||||
it "does not create user when email not in allow list" do
|
||||
post "/users", params:
|
||||
{ user: { name: "ronald #{rand(10)}",
|
||||
username: "mcdonald_#{rand(10)}",
|
||||
email: "ronald@mcdonald.com",
|
||||
password: "PaSSw0rd_yo000",
|
||||
password_confirmation: "PaSSw0rd_yo000" } }
|
||||
expect(User.all.size).to be 0
|
||||
end
|
||||
|
||||
it "creates user when email in allow list" do
|
||||
post "/users", params:
|
||||
{ user: { name: "royal #{rand(10)}",
|
||||
username: "magoo_#{rand(10)}",
|
||||
email: "queenelizabeth@dev.to",
|
||||
password: "PaSSw0rd_yo000",
|
||||
password_confirmation: "PaSSw0rd_yo000" } }
|
||||
expect(User.all.size).to be 1
|
||||
end
|
||||
end
|
||||
|
||||
context "when site configured to accept email registration AND require captcha" do
|
||||
before do
|
||||
allow(SiteConfig).to receive(:allow_email_password_registration).and_return(true)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue