Project

General

Profile

Feature #3369 » 3369-restrict-domains-v3.patch

Go MAEDA, 2020-04-29 09:03

View differences:

app/models/email_address.rb
36 36
  validates_length_of :address, :maximum => User::MAIL_LENGTH_LIMIT, :allow_nil => true
37 37
  validates_uniqueness_of :address, :case_sensitive => false,
38 38
    :if => Proc.new {|email| email.address_changed? && email.address.present?}
39
  validate :validate_email_domain, :if => proc {|email| email.address.present?}
39 40

  
40 41
  safe_attributes 'address'
41 42

  
......
51 52
    end
52 53
  end
53 54

  
55
  # Returns true if the email domain is allowed regarding allowed/denied
56
  # domains defined in application settings, otherwise false
57
  def self.valid_domain?(domain_or_email)
58
    denied, allowed =
59
      [:email_domains_denied, :email_domains_allowed].map do |setting|
60
        Setting.__send__(setting)
61
      end
62
    domain = domain_or_email.split('@').last
63
    return false if denied.present? && domain_in?(domain, denied)
64
    return false if allowed.present? && !domain_in?(domain, allowed)
65
    true
66
  end
67

  
68
  # Returns true if domain belongs to domains list.
69
  def self.domain_in?(domain, domains)
70
    domain = domain.downcase
71
    domains = domains.to_s.split(/[\s,]+/) unless domains.is_a?(Array)
72
    domains.reject(&:blank?).map(&:downcase).any? do |s|
73
      s.start_with?('.') ? domain.end_with?(s) : domain == s
74
    end
75
  end
76

  
54 77
  private
55 78

  
56 79
  # send a security notification to user that a new email address was added
......
117 140
      Token.where(:user_id => user_id, :action => tokens).delete_all
118 141
    end
119 142
  end
143

  
144
  def validate_email_domain
145
    unless self.class.valid_domain?(address)
146
      errors.add(:address, :invalid)
147
    end
148
  end
120 149
end
app/views/settings/_users.html.erb
3 3
  <div class="box tabular settings">
4 4
    <p><%= setting_text_field :max_additional_emails, :size => 6 %></p>
5 5

  
6
    <p><%= setting_text_area :email_domains_allowed %>
7
    <em class="info"><%= l(:text_comma_separated) %> <%= l(:label_example) %>: example.com, example.org</em></p>
8

  
9
    <p><%= setting_text_area :email_domains_denied %>
10
    <em class="info"><%= l(:text_comma_separated) %> <%= l(:label_example) %>: .example.com, foo.example.org, example.net</em></p>
11

  
6 12
    <p><%= setting_check_box :unsubscribe %></p>
7 13
  </div>
8 14

  
config/locales/en.yml
479 479
  setting_force_default_language_for_loggedin: Force default language for logged-in users
480 480
  setting_link_copied_issue: Link issues on copy
481 481
  setting_max_additional_emails: Maximum number of additional email addresses
482
  setting_email_domains_allowed: Allowed email domains
483
  setting_email_domains_denied: Disallowed email domains
482 484
  setting_search_results_per_page: Search results per page
483 485
  setting_attachment_extensions_allowed: Allowed extensions
484 486
  setting_attachment_extensions_denied: Disallowed extensions
config/settings.yml
53 53
max_additional_emails:
54 54
  format: int
55 55
  default: 5
56
email_domains_allowed:
57
  default:
58
email_domains_denied:
59
  default:
56 60
# Maximum lifetime of user sessions in minutes
57 61
session_lifetime:
58 62
  format: int
test/functional/email_addresses_controller_test.rb
118 118
    end
119 119
  end
120 120

  
121
  def test_create_with_disallowed_domain_should_fail
122
    @request.session[:user_id] = 2
123

  
124
    with_settings :email_domains_denied => 'black.example' do
125
      assert_no_difference 'EmailAddress.count' do
126
        post :create, :params => {
127
            :user_id => 2,
128
            :email_address => {
129
              :address => 'another@black.example'
130
            }
131
          }
132
        assert_response :success
133
        assert_select_error 'Email is invalid'
134
      end
135
    end
136

  
137
    with_settings :email_domains_allowed => 'white.example' do
138
      assert_no_difference 'EmailAddress.count' do
139
        post :create, :params => {
140
            :user_id => 2,
141
            :email_address => {
142
              :address => 'something@example.fr'
143
            }
144
          }
145
        assert_response :success
146
        assert_select_error 'Email is invalid'
147
      end
148
    end
149
  end
150

  
121 151
  def test_create_should_send_security_notification
122 152
    @request.session[:user_id] = 2
123 153
    ActionMailer::Base.deliveries.clear
test/unit/email_address_test.rb
30 30
    email = EmailAddress.new(address: 'jsmith@example.xn--80akhbyknj4f')
31 31
    assert email.valid?
32 32
  end
33

  
34
  def test_address_should_be_validated_against_denied_domains
35
    with_settings :email_domains_denied => "black.test\r\nBLACK.EXAMPLE, .subdomain.test" do
36
      email = EmailAddress.new(address: 'user@black.test')
37
      assert_not email.valid?
38
      email = EmailAddress.new(address: 'user@notblack.test')
39
      assert email.valid?
40
      email = EmailAddress.new(address: 'user@BLACK.TEST')
41
      assert_not email.valid?
42
      email = EmailAddress.new(address: 'user@black.example')
43
      assert_not email.valid?
44
      email = EmailAddress.new(address: 'user@subdomain.test')
45
      assert email.valid?
46
      email = EmailAddress.new(address: 'user@foo.subdomain.test')
47
      assert_not email.valid?
48
    end
49
  end
50

  
51
  def test_address_should_be_validated_against_allowed_domains
52
    with_settings :email_domains_allowed => "white.test\r\nWHITE.EXAMPLE, .subdomain.test" do
53
      email = EmailAddress.new(address: 'user@white.test')
54
      assert email.valid?
55
      email = EmailAddress.new(address: 'user@notwhite.test')
56
      assert_not email.valid?
57
      email = EmailAddress.new(address: 'user@WHITE.TEST')
58
      assert email.valid?
59
      email = EmailAddress.new(address: 'user@white.example')
60
      assert email.valid?
61
      email = EmailAddress.new(address: 'user@subdomain.test')
62
      assert_not email.valid?
63
      email = EmailAddress.new(address: 'user@foo.subdomain.test')
64
      assert email.valid?
65
    end
66
  end
33 67
end
(4-4/4)