diff options
-rw-r--r-- | app/controllers/settings_controller.rb | 5 | ||||
-rw-r--r-- | app/models/mailer.rb | 16 | ||||
-rw-r--r-- | app/models/setting.rb | 17 | ||||
-rw-r--r-- | app/views/mailer/settings_updated.html.erb | 14 | ||||
-rw-r--r-- | app/views/mailer/settings_updated.text.erb | 12 | ||||
-rw-r--r-- | config/locales/en.yml | 1 | ||||
-rw-r--r-- | config/locales/fr.yml | 1 | ||||
-rw-r--r-- | config/settings.yml | 16 | ||||
-rw-r--r-- | test/functional/settings_controller_test.rb | 38 |
9 files changed, 116 insertions, 4 deletions
diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index 5ca5d1dab..c7741c053 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -33,10 +33,7 @@ class SettingsController < ApplicationController def edit @notifiables = Redmine::Notifiable.all if request.post? && params[:settings] && params[:settings].is_a?(Hash) - settings = (params[:settings] || {}).dup.symbolize_keys - settings.each do |name, value| - Setting.set_from_params name, value - end + Setting.set_all_from_params(params[:settings]) flash[:notice] = l(:notice_successful_update) redirect_to settings_path(:tab => params[:tab]) else diff --git a/app/models/mailer.rb b/app/models/mailer.rb index a803a35c2..4891ff5bf 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -332,6 +332,22 @@ class Mailer < ActionMailer::Base :subject => l(:mail_subject_security_notification) end + def settings_updated(recipients, changes) + redmine_headers 'Sender' => User.current.login + @changes = changes + @url = url_for(controller: 'settings', action: 'index') + mail :to => recipients, + :subject => l(:mail_subject_security_notification) + end + + # Notifies admins about settings changes + def self.security_settings_updated(changes) + return unless changes.present? + + users = User.active.where(admin: true).to_a + Mailer.settings_updated(users, changes).deliver + end + def test_email(user) set_language_if_valid(user.language) @url = url_for(:controller => 'welcome') diff --git a/app/models/setting.rb b/app/models/setting.rb index 2574649f3..bbcdfc72a 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -118,6 +118,23 @@ class Setting < ActiveRecord::Base setting.value end + # Updates multiple settings from params and sends a security notification if needed + def self.set_all_from_params(settings) + settings = (settings || {}).dup.symbolize_keys + changes = [] + settings.each do |name, value| + previous_value = Setting[name] + set_from_params name, value + if available_settings[name.to_s]['security_notifications'] && Setting[name] != previous_value + changes << name + end + end + if changes.any? + Mailer.security_settings_updated(changes) + end + true + end + # Sets a setting value from params def self.set_from_params(name, params) params = params.dup diff --git a/app/views/mailer/settings_updated.html.erb b/app/views/mailer/settings_updated.html.erb new file mode 100644 index 000000000..8596089a2 --- /dev/null +++ b/app/views/mailer/settings_updated.html.erb @@ -0,0 +1,14 @@ +<p><%= l(:mail_body_settings_updated) %></p> + +<ul> +<% @changes.each do |name| %> + <li><%= l("setting_#{name}") %></li> +<% end %> +</ul> + +<%= link_to @url, @url %> + +<p><%= l(:field_user) %>: <strong><%= User.current.login %></strong><br/> +<%= l(:field_remote_ip) %>: <strong><%= User.current.remote_ip %></strong><br/> +<%= l(:label_date) %>: <strong><%= format_time Time.now, true %></strong></p> + diff --git a/app/views/mailer/settings_updated.text.erb b/app/views/mailer/settings_updated.text.erb new file mode 100644 index 000000000..51a2a8f6a --- /dev/null +++ b/app/views/mailer/settings_updated.text.erb @@ -0,0 +1,12 @@ +<%= l(:mail_body_settings_updated) %> + +<% @changes.each do |name| %> + * <%= l("setting_#{name}") %> +<% end %> + +<%= @url %> + +<%= l(:field_user) %>: <%= User.current.login %> +<%= l(:field_remote_ip) %>: <%= User.current.remote_ip %> +<%= l(:label_date) %>: <%= format_time Time.now, true %> + diff --git a/config/locales/en.yml b/config/locales/en.yml index 8a314511a..a2ac47903 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -235,6 +235,7 @@ en: mail_body_security_notification_remove: "%{field} %{value} was removed." mail_body_security_notification_notify_enabled: "Email address %{value} now receives notifications." mail_body_security_notification_notify_disabled: "Email address %{value} no longer receives notifications." + mail_body_settings_updated: "The following settings were changed:" field_name: Name field_description: Description diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 90984c871..41cfd55c9 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -248,6 +248,7 @@ fr: mail_body_wiki_content_added: "La page wiki '%{id}' a été ajoutée par %{author}." mail_subject_wiki_content_updated: "Page wiki '%{id}' mise à jour" mail_body_wiki_content_updated: "La page wiki '%{id}' a été mise à jour par %{author}." + mail_body_settings_updated: "Les paramètres suivants ont été modifiés :" field_name: Nom field_description: Description diff --git a/config/settings.yml b/config/settings.yml index 5031b68d3..49e1edcd3 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -27,19 +27,24 @@ welcome_text: default: login_required: default: 0 + security_notifications: 1 self_registration: default: '2' + security_notifications: 1 lost_password: default: 1 + security_notifications: 1 unsubscribe: default: 1 password_min_length: format: int default: 8 + security_notifications: 1 # Maximum password age in days password_max_age: format: int default: 0 + security_notifications: 1 # Maximum number of additional email addresses per user max_additional_emails: format: int @@ -48,10 +53,12 @@ max_additional_emails: session_lifetime: format: int default: 0 + security_notifications: 1 # User session timeout in minutes session_timeout: format: int default: 0 + security_notifications: 1 attachment_max_size: format: int default: 5120 @@ -91,6 +98,7 @@ host_name: default: localhost:3000 protocol: default: http + security_notifications: 1 feeds_limit: format: int default: 15 @@ -114,12 +122,15 @@ enabled_scm: - Cvs - Bazaar - Git + security_notifications: 1 autofetch_changesets: default: 1 sys_api_enabled: default: 0 + security_notifications: 1 sys_api_key: default: '' + security_notifications: 1 commit_cross_project_ref: default: 0 commit_ref_keywords: @@ -173,8 +184,10 @@ mail_handler_excluded_filenames: default: '' mail_handler_api_enabled: default: 0 + security_notifications: 1 mail_handler_api_key: default: + security_notifications: 1 issue_list_default_columns: serialized: true default: @@ -237,14 +250,17 @@ gravatar_enabled: default: 0 openid: default: 0 + security_notifications: 1 gravatar_default: default: '' start_of_week: default: '' rest_api_enabled: default: 0 + security_notifications: 1 jsonp_enabled: default: 0 + security_notifications: 1 default_notification_option: default: 'only_my_events' emails_header: diff --git a/test/functional/settings_controller_test.rb b/test/functional/settings_controller_test.rb index de5fddd8a..139eb7845 100644 --- a/test/functional/settings_controller_test.rb +++ b/test/functional/settings_controller_test.rb @@ -136,6 +136,44 @@ class SettingsControllerTest < ActionController::TestCase ], Setting.commit_update_keywords) end + def test_post_edit_should_send_security_notification_for_notified_settings + ActionMailer::Base.deliveries.clear + post :edit, :settings => { + :login_required => 1 + } + + assert_not_nil (mail = ActionMailer::Base.deliveries.last) + assert_mail_body_match '0.0.0.0', mail + assert_mail_body_match I18n.t(:setting_login_required), mail + assert_select_email do + assert_select 'a[href^=?]', 'http://localhost:3000/settings' + end + # All admins should receive this + recipients = [mail.bcc, mail.cc].flatten + User.active.where(admin: true).each do |admin| + assert_include admin.mail, recipients + end + end + + def test_post_edit_should_not_send_security_notification_for_non_notified_settings + ActionMailer::Base.deliveries.clear + post :edit, :settings => { + :app_title => 'MineRed' + } + + assert_nil (mail = ActionMailer::Base.deliveries.last) + end + + def test_post_edit_should_not_send_security_notification_for_unchanged_settings + ActionMailer::Base.deliveries.clear + post :edit, :settings => { + :login_required => 0 + } + + assert_nil (mail = ActionMailer::Base.deliveries.last) + end + + def test_get_plugin_settings ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins")) Redmine::Plugin.register :foo do |