diff --git a/Dockerfile.public b/Dockerfile.public index 8d2245a1bd..3005145c85 100644 --- a/Dockerfile.public +++ b/Dockerfile.public @@ -7,6 +7,7 @@ ENV HEROKU=true ENV ATTACHMENTS_STORAGE_PATH=/var/db/openproject/files ENV RAILS_CACHE_STORE=memcache ENV SECRET_KEY_BASE=OVERWRITE_ME +ENV OPENPROJECT_INSTALLATION__TYPE=docker USER root RUN apt-get update -qq && \ diff --git a/app/helpers/security_badge_helper.rb b/app/helpers/security_badge_helper.rb new file mode 100644 index 0000000000..d7c6c10c66 --- /dev/null +++ b/app/helpers/security_badge_helper.rb @@ -0,0 +1,44 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +module SecurityBadgeHelper + def security_badge_url(args = {}) + uri = URI.parse(OpenProject::Configuration[:security_badge_url]) + info = { + uuid: Setting.installation_uuid, + type: OpenProject::Configuration[:installation_type], + version: OpenProject::VERSION.to_s, + db: ActiveRecord::Base.connection.adapter_name.downcase, + lang: User.current.try(:language), + ee: EnterpriseToken.current.present?, + }.merge(args.symbolize_keys) + uri.query = info.to_query + uri.to_s + end +end diff --git a/app/views/admin/info.html.erb b/app/views/admin/info.html.erb index 0ae615930f..708a740ce7 100644 --- a/app/views/admin/info.html.erb +++ b/app/views/admin/info.html.erb @@ -48,6 +48,16 @@ See docs/COPYRIGHT.rdoc for more details. <%= OpenProject::Info.versioned_name %> (<%= @db_adapter_name %>) + <% if Setting.security_badge_displayed? %> +
+
+
+ <%= content_tag :span do %> + <%= content_tag :object, nil, data: security_badge_url, type: "image/svg+xml" %> + <% end %> +
+
+ <% end %> <% if (updated_on = OpenProject::VERSION.updated_on).present? %>
<%= l(:label_last_change_on) %>
diff --git a/app/views/homescreen/blocks/_administration.html.erb b/app/views/homescreen/blocks/_administration.html.erb index 6bfa6f9814..4c050ed3a0 100644 --- a/app/views/homescreen/blocks/_administration.html.erb +++ b/app/views/homescreen/blocks/_administration.html.erb @@ -47,5 +47,9 @@ <%= link_to t(:label_custom_style), custom_style_path, title: t(:label_custom_style) %> + <%= content_tag :li do %> + <%= content_tag :object, nil, data: security_badge_url, type: "image/svg+xml", style: "vertical-align:top;" %> + <% end if Setting.security_badge_displayed? %> + <%= call_hook(:homescreen_administration_links) %> diff --git a/app/views/settings/_general.html.erb b/app/views/settings/_general.html.erb index 5bc2cf79b5..411b0126c4 100644 --- a/app/views/settings/_general.html.erb +++ b/app/views/settings/_general.html.erb @@ -57,6 +57,12 @@ See docs/COPYRIGHT.rdoc for more details. <%= setting_text_field :file_max_size_displayed, size: 6, unit: t(:"number.human.storage_units.units.kb"), container_class: '-xslim' %>
<%= setting_text_field :diff_max_lines_displayed, size: 6, container_class: '-xslim' %>
+
+ <%= setting_check_box :security_badge_displayed %> + + <%= t(:text_notice_security_badge_displayed_html, information_panel_label: t(:label_information), information_panel_path: info_admin_index_path) %> + +
<%= call_hook(:view_settings_general_form) %>
<%= t(:setting_welcome_text) %> diff --git a/config/initializers/secure_headers.rb b/config/initializers/secure_headers.rb index 564345ef4d..a7fef1eedd 100644 --- a/config/initializers/secure_headers.rb +++ b/config/initializers/secure_headers.rb @@ -18,6 +18,7 @@ SecureHeaders::Configuration.default do |config| # Valid for iframes frame_src = %w['self' https://player.vimeo.com] + frame_src << OpenProject::Configuration[:security_badge_url] # Default src default_src = %w('self') @@ -61,8 +62,8 @@ SecureHeaders::Configuration.default do |config| script_src: script_src, # Allow unsafe-inline styles style_src: assets_src + %w('unsafe-inline'), - # disallow all object-src - object_src: %w('none'), + # Allow object-src from Release API + object_src: [OpenProject::Configuration[:security_badge_url]], # Connect sources for CLI in dev mode connect_src: connect_src diff --git a/config/initializers/security_badge.rb b/config/initializers/security_badge.rb new file mode 100644 index 0000000000..b350a825c0 --- /dev/null +++ b/config/initializers/security_badge.rb @@ -0,0 +1,7 @@ +OpenProject::Application.configure do + config.after_initialize do + if Setting.settings_table_exists_yet? + Setting.installation_uuid ||= SecureRandom.uuid + end + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 02ea486b64..18a503f933 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2083,6 +2083,7 @@ en: setting_per_page_options: "Objects per page options" setting_plain_text_mail: "Plain text mail (no HTML)" setting_protocol: "Protocol" + setting_security_badge_displayed: "Display security badge" setting_registration_footer: "Registration footer" setting_repositories_automatic_managed_vendor: "Automatic repository vendor type" setting_repositories_encodings: "Repositories encodings" @@ -2228,6 +2229,7 @@ en: text_no_configuration_data: "Roles, types, work package statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." text_no_notes: "There are no comments available for this work package." text_notice_too_many_values_are_inperformant: "Note: Displaying more than 100 items per page can increase the page load time." + text_notice_security_badge_displayed_html: "Note: if enabled, this will display a badge with your installation status in the %{information_panel_label} administration panel, and on the home page. It is displayed to administrators only. The badge will run a check of your current OpenProject version against the official OpenProject release database to alert you of any updates or known vulnerabilities." text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" text_plugin_assets_writable: "Plugin assets directory writable" text_powered_by: "Powered by %{link}" diff --git a/config/settings.yml b/config/settings.yml index dac5d25457..ae3265bd89 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -364,3 +364,7 @@ api_max_page_size: default: 500 demo_projects_available: default: false +security_badge_displayed: + default: true +installation_uuid: + default: null diff --git a/lib/open_project/configuration.rb b/lib/open_project/configuration.rb index 7e5210ca55..f6f40b1ff3 100644 --- a/lib/open_project/configuration.rb +++ b/lib/open_project/configuration.rb @@ -124,7 +124,10 @@ module OpenProject # Allow in-context translations to be loaded with CSP 'crowdin_in_context_translations' => true, - 'registration_footer' => {} + 'registration_footer' => {}, + + 'installation_type' => "manual", + 'security_badge_url' => "https://releases.openproject.com/v1/check.svg" } @config = nil diff --git a/spec/helpers/security_badge_helper_spec.rb b/spec/helpers/security_badge_helper_spec.rb new file mode 100644 index 0000000000..b885a80359 --- /dev/null +++ b/spec/helpers/security_badge_helper_spec.rb @@ -0,0 +1,44 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2017 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe SecurityBadgeHelper, type: :helper do + describe '#security_badge_url', with_settings: { installation_uuid: 'abcd1234' } do + it "generates a URL with the release API path and the details of the installation" do + uri = URI.parse(helper.security_badge_url) + query = Rack::Utils.parse_nested_query(uri.query) + expect(uri.host).to eq("releases.openproject.com") + expect(query.keys).to match_array(["uuid", "type", "version", "db", "lang", "ee"]) + expect(query["uuid"]).to eq("abcd1234") + expect(query["version"]).to eq(OpenProject::VERSION.to_s) + expect(query["type"]).to eq("manual") + expect(query["ee"]).to eq("false") + end + end +end