Patch by Yuichi HARADA and Go MAEDA. git-svn-id: http://svn.redmine.org/redmine/trunk@19735 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/4.2.0
validates_length_of :address, :maximum => User::MAIL_LENGTH_LIMIT, :allow_nil => true | validates_length_of :address, :maximum => User::MAIL_LENGTH_LIMIT, :allow_nil => true | ||||
validates_uniqueness_of :address, :case_sensitive => false, | validates_uniqueness_of :address, :case_sensitive => false, | ||||
:if => Proc.new {|email| email.address_changed? && email.address.present?} | :if => Proc.new {|email| email.address_changed? && email.address.present?} | ||||
validate :validate_email_domain, :if => proc {|email| email.address.present?} | |||||
safe_attributes 'address' | safe_attributes 'address' | ||||
end | end | ||||
end | end | ||||
# Returns true if the email domain is allowed regarding allowed/denied | |||||
# domains defined in application settings, otherwise false | |||||
def self.valid_domain?(domain_or_email) | |||||
denied, allowed = | |||||
[:email_domains_denied, :email_domains_allowed].map do |setting| | |||||
Setting.__send__(setting) | |||||
end | |||||
domain = domain_or_email.split('@').last | |||||
return false if denied.present? && domain_in?(domain, denied) | |||||
return false if allowed.present? && !domain_in?(domain, allowed) | |||||
true | |||||
end | |||||
# Returns true if domain belongs to domains list. | |||||
def self.domain_in?(domain, domains) | |||||
domain = domain.downcase | |||||
domains = domains.to_s.split(/[\s,]+/) unless domains.is_a?(Array) | |||||
domains.reject(&:blank?).map(&:downcase).any? do |s| | |||||
s.start_with?('.') ? domain.end_with?(s) : domain == s | |||||
end | |||||
end | |||||
private | private | ||||
# send a security notification to user that a new email address was added | # send a security notification to user that a new email address was added | ||||
Token.where(:user_id => user_id, :action => tokens).delete_all | Token.where(:user_id => user_id, :action => tokens).delete_all | ||||
end | end | ||||
end | end | ||||
def validate_email_domain | |||||
errors.add(:address, :invalid) unless self.class.valid_domain?(address) | |||||
end | |||||
end | end |
<div class="box tabular settings"> | <div class="box tabular settings"> | ||||
<p><%= setting_text_field :max_additional_emails, :size => 6 %></p> | <p><%= setting_text_field :max_additional_emails, :size => 6 %></p> | ||||
<p><%= setting_text_area :email_domains_allowed %> | |||||
<em class="info"><%= l(:text_comma_separated) %> <%= l(:label_example) %>: example.com, example.org</em></p> | |||||
<p><%= setting_text_area :email_domains_denied %> | |||||
<em class="info"><%= l(:text_comma_separated) %> <%= l(:label_example) %>: .example.com, foo.example.org, example.net</em></p> | |||||
<p><%= setting_check_box :unsubscribe %></p> | <p><%= setting_check_box :unsubscribe %></p> | ||||
</div> | </div> | ||||
setting_force_default_language_for_loggedin: Force default language for logged-in users | setting_force_default_language_for_loggedin: Force default language for logged-in users | ||||
setting_link_copied_issue: Link issues on copy | setting_link_copied_issue: Link issues on copy | ||||
setting_max_additional_emails: Maximum number of additional email addresses | setting_max_additional_emails: Maximum number of additional email addresses | ||||
setting_email_domains_allowed: Allowed email domains | |||||
setting_email_domains_denied: Disallowed email domains | |||||
setting_search_results_per_page: Search results per page | setting_search_results_per_page: Search results per page | ||||
setting_attachment_extensions_allowed: Allowed extensions | setting_attachment_extensions_allowed: Allowed extensions | ||||
setting_attachment_extensions_denied: Disallowed extensions | setting_attachment_extensions_denied: Disallowed extensions |
max_additional_emails: | max_additional_emails: | ||||
format: int | format: int | ||||
default: 5 | default: 5 | ||||
email_domains_allowed: | |||||
default: | |||||
email_domains_denied: | |||||
default: | |||||
# Maximum lifetime of user sessions in minutes | # Maximum lifetime of user sessions in minutes | ||||
session_lifetime: | session_lifetime: | ||||
format: int | format: int |
end | end | ||||
end | end | ||||
def test_create_with_disallowed_domain_should_fail | |||||
@request.session[:user_id] = 2 | |||||
with_settings :email_domains_denied => 'black.example' do | |||||
assert_no_difference 'EmailAddress.count' do | |||||
post :create, :params => { | |||||
:user_id => 2, | |||||
:email_address => { | |||||
:address => 'another@black.example' | |||||
} | |||||
} | |||||
assert_response :success | |||||
assert_select_error 'Email is invalid' | |||||
end | |||||
end | |||||
with_settings :email_domains_allowed => 'white.example' do | |||||
assert_no_difference 'EmailAddress.count' do | |||||
post :create, :params => { | |||||
:user_id => 2, | |||||
:email_address => { | |||||
:address => 'something@example.fr' | |||||
} | |||||
} | |||||
assert_response :success | |||||
assert_select_error 'Email is invalid' | |||||
end | |||||
end | |||||
end | |||||
def test_create_should_send_security_notification | def test_create_should_send_security_notification | ||||
@request.session[:user_id] = 2 | @request.session[:user_id] = 2 | ||||
ActionMailer::Base.deliveries.clear | ActionMailer::Base.deliveries.clear |
email = EmailAddress.new(address: 'jsmith@example.xn--80akhbyknj4f') | email = EmailAddress.new(address: 'jsmith@example.xn--80akhbyknj4f') | ||||
assert email.valid? | assert email.valid? | ||||
end | end | ||||
def test_address_should_be_validated_against_denied_domains | |||||
with_settings :email_domains_denied => "black.test\r\nBLACK.EXAMPLE, .subdomain.test" do | |||||
email = EmailAddress.new(address: 'user@black.test') | |||||
assert_not email.valid? | |||||
email = EmailAddress.new(address: 'user@notblack.test') | |||||
assert email.valid? | |||||
email = EmailAddress.new(address: 'user@BLACK.TEST') | |||||
assert_not email.valid? | |||||
email = EmailAddress.new(address: 'user@black.example') | |||||
assert_not email.valid? | |||||
email = EmailAddress.new(address: 'user@subdomain.test') | |||||
assert email.valid? | |||||
email = EmailAddress.new(address: 'user@foo.subdomain.test') | |||||
assert_not email.valid? | |||||
end | |||||
end | |||||
def test_address_should_be_validated_against_allowed_domains | |||||
with_settings :email_domains_allowed => "white.test\r\nWHITE.EXAMPLE, .subdomain.test" do | |||||
email = EmailAddress.new(address: 'user@white.test') | |||||
assert email.valid? | |||||
email = EmailAddress.new(address: 'user@notwhite.test') | |||||
assert_not email.valid? | |||||
email = EmailAddress.new(address: 'user@WHITE.TEST') | |||||
assert email.valid? | |||||
email = EmailAddress.new(address: 'user@white.example') | |||||
assert email.valid? | |||||
email = EmailAddress.new(address: 'user@subdomain.test') | |||||
assert_not email.valid? | |||||
email = EmailAddress.new(address: 'user@foo.subdomain.test') | |||||
assert email.valid? | |||||
end | |||||
end | |||||
end | end |