diff --git a/Gemfile b/Gemfile index 14aec14508e..d01e2b83b57 100644 --- a/Gemfile +++ b/Gemfile @@ -194,7 +194,7 @@ gem "rack-timeout", "~> 0.7.0", require: "rack/timeout/base" gem "nokogiri", "~> 1.19.0" -gem "carrierwave", "~> 1.3.4" +gem "carrierwave", "~> 2.2.6" gem "carrierwave_direct", "~> 2.1.0" gem "fog-aws" diff --git a/Gemfile.lock b/Gemfile.lock index 54235568b40..5acdbbddc5c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -408,11 +408,14 @@ GEM capybara-screenshot (1.0.26) capybara (>= 1.0, < 4) launchy - carrierwave (1.3.4) - activemodel (>= 4.0.0) - activesupport (>= 4.0.0) - mime-types (>= 1.16) - ssrf_filter (~> 1.0, < 1.1.0) + carrierwave (2.2.6) + activemodel (>= 5.0.0) + activesupport (>= 5.0.0) + addressable (~> 2.6) + image_processing (~> 1.1) + marcel (~> 1.0.0) + mini_mime (>= 0.1.3) + ssrf_filter (~> 1.0) carrierwave_direct (2.1.0) carrierwave (>= 1.0.0) fog-aws @@ -719,6 +722,9 @@ GEM ostruct ice_cube (0.17.0) ice_nine (0.11.2) + image_processing (1.14.0) + mini_magick (>= 4.9.5, < 6) + ruby-vips (>= 2.0.17, < 3) inline_svg (1.10.0) activesupport (>= 3.0) nokogiri (>= 1.6) @@ -803,7 +809,7 @@ GEM net-imap net-pop net-smtp - marcel (1.1.0) + marcel (1.0.4) markly (0.15.2) matrix (0.4.3) mcp (0.4.0) @@ -1366,6 +1372,9 @@ GEM ruby-saml (1.18.1) nokogiri (>= 1.13.10) rexml + ruby-vips (2.3.0) + ffi (~> 1.12) + logger ruby2_keywords (0.0.5) rubytree (2.2.0) json (~> 2.0, > 2.9) @@ -1570,7 +1579,7 @@ DEPENDENCIES capybara (~> 3.40.0) capybara-screenshot (~> 1.0.17) capybara_accessible_selectors! - carrierwave (~> 1.3.4) + carrierwave (~> 2.2.6) carrierwave_direct (~> 2.1.0) climate_control closure_tree (~> 9.5.0) @@ -1824,7 +1833,7 @@ CHECKSUMS capybara (3.40.0) sha256=42dba720578ea1ca65fd7a41d163dd368502c191804558f6e0f71b391054aeef capybara-screenshot (1.0.26) sha256=816b9370a07752097c82a05f568aaf5d3b7f45c3db5d3aab2014071e1b3c0c77 capybara_accessible_selectors (0.15.0) - carrierwave (1.3.4) sha256=81772dabd1830edbd7f4526d2ae2c79f974f1d48900c3f03f7ecb7c657463a21 + carrierwave (2.2.6) sha256=cd9b6108fc7544e97e7fbcc561bd319a09f23c96816fdd0df8f2f45ffdc0dac3 carrierwave_direct (2.1.0) sha256=b0d5c19c1d17a05940e488cff644a3b2946422d6d494b2174b48f6a90c5dddbf cbor (0.5.10.1) sha256=79cdf79f18dcd9ee97e0b849c6d573e5a2e3ddc1954d180f384d6ed2612b6df0 cgi (0.5.1) sha256=e93fcafc69b8a934fe1e6146121fa35430efa8b4a4047c4893764067036f18e9 @@ -1955,6 +1964,7 @@ CHECKSUMS icalendar (2.12.1) sha256=ecff56c550aed551f29ad1faad0da54bf62362dfaf22a428bd7ad782938fe764 ice_cube (0.17.0) sha256=32deb45dda4b4acc53505c2f581f6d32b5afc04d29b9004769944a0df5a5fcbe ice_nine (0.11.2) sha256=5d506a7d2723d5592dc121b9928e4931742730131f22a1a37649df1c1e2e63db + image_processing (1.14.0) sha256=754cc169c9c262980889bec6bfd325ed1dafad34f85242b5a07b60af004742fb inline_svg (1.10.0) sha256=5b652934236fd9f8adc61f3fd6e208b7ca3282698b19f28659971da84bf9a10f interception (0.5) sha256=a53818d636752a8df90d8c1bb2f7b6e13a7b828543cb02b50fbde98b849d7907 io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc @@ -1982,7 +1992,7 @@ CHECKSUMS loofah (2.25.0) sha256=df5ed7ac3bac6a4ec802df3877ee5cc86d027299f8952e6243b3dac446b060e6 lookbook (2.3.14) sha256=c11a693bde9915b553c4463440ad5e750829f90bff08abdb6b8610373864cd7c mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941 - marcel (1.1.0) sha256=fdcfcfa33cc52e93c4308d40e4090a5d4ea279e160a7f6af988260fa970e0bee + marcel (1.0.4) sha256=0d5649feb64b8f19f3d3468b96c680bae9746335d02194270287868a661516a4 markly (0.15.2) sha256=65dae965d4dd4ecd997fba43b93acc0fe7dadfec6f07a748640c7a9299a8551e matrix (0.4.3) sha256=a0d5ab7ddcc1973ff690ab361b67f359acbb16958d1dc072b8b956a286564c5b mcp (0.4.0) sha256=4d1dd2b99fbd81a5fdc808d258c38a4f57dd69751ee1e5f62b3ab40e31625a36 @@ -2216,6 +2226,7 @@ CHECKSUMS ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 ruby-rc4 (0.1.5) sha256=00cc40a39d20b53f5459e7ea006a92cf584e9bc275e2a6f7aa1515510e896c03 ruby-saml (1.18.1) sha256=1b0e7a44aef150b4197955f5e015d593672e242cfdc5d06aa7554ec2350b9107 + ruby-vips (2.3.0) sha256=e685ec02c13969912debbd98019e50492e12989282da5f37d05f5471442f5374 ruby2_keywords (0.0.5) sha256=ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef rubytree (2.2.0) sha256=e312dc1ed814153583b57d9662e6caac1fd60830886a571b48bb06daef906eb6 rubyzip (2.4.1) sha256=8577c88edc1fde8935eb91064c5cb1aef9ad5494b940cf19c775ee833e075615 diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb index 78862f69417..e6e4b85f366 100644 --- a/config/initializers/carrierwave.rb +++ b/config/initializers/carrierwave.rb @@ -56,6 +56,12 @@ module CarrierWave end end +# CW 2.0 changed the default cache_storage from :file to nil. +# Restore :file to keep Attachment.clean_cached_files! working. +CarrierWave.configure do |config| + config.cache_storage = :file +end + unless OpenProject::Configuration.fog_credentials.empty? CarrierWave::Configuration.configure_fog! end diff --git a/lib/open_project/patches/carrierwave_fog_file.rb b/lib/open_project/patches/carrierwave_fog_file.rb deleted file mode 100644 index c1aca617364..00000000000 --- a/lib/open_project/patches/carrierwave_fog_file.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require "carrierwave/storage/fog" - -## -# Code copied straight from the CarrierWave source. -# All we did is add `options[:expire_at]`. -# -# @todo Upgrade to CarrierWave 2.0.2 to make this patch obsolete. - -module OpenProject::Patches::FogFile - extend ActiveSupport::Concern - - included do - def authenticated_url(options = {}) # rubocop:disable Metrics/AbcSize - if ["AWS", "Google", "Rackspace", "OpenStack"].include?(@uploader.fog_credentials[:provider]) - # avoid a get by using local references - local_directory = connection.directories.new(key: @uploader.fog_directory) - local_file = local_directory.files.new(key: path) - expire_at = options[:expire_at] || (::Fog::Time.now + @uploader.fog_authenticated_url_expiration) - case @uploader.fog_credentials[:provider] - when "AWS", "Google" - # Older versions of fog-google do not support options as a parameter - if url_options_supported?(local_file) - local_file.url(expire_at, options) - else - warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider." - local_file.url(expire_at) - end - when "Rackspace" - connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options) - when "OpenStack" - connection.get_object_https_url(@uploader.fog_directory, path, expire_at) - else - local_file.url(expire_at) - end - end - end - end -end - -OpenProject::Patches.patch_gem_version "carrierwave", "1.3.4" do - CarrierWave::Storage::Fog::File.include OpenProject::Patches::FogFile -end diff --git a/lib/open_project/patches/carrierwave_sanitized_file.rb b/lib/open_project/patches/carrierwave_sanitized_file.rb deleted file mode 100644 index 33d8fa02316..00000000000 --- a/lib/open_project/patches/carrierwave_sanitized_file.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) the OpenProject GmbH -# -# 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-2013 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 COPYRIGHT and LICENSE files for more details. -#++ -require "carrierwave" - -## -# Adapt carrierwave to match fixes for CVE-2023-49090. -# https://github.com/carrierwaveuploader/carrierwave/security/advisories/GHSA-vfmv-jfc5-pjjw -module OpenProject::Patches::CarrierwaveSanitizedFile - extend ActiveSupport::Concern - - included do - def content_type - return @content_type if @content_type - - if @file.respond_to?(:content_type) and @file.content_type - Marcel::MimeType.for(declared_type: @file.content_type.to_s.chomp) - elsif path - @content_type = Attachment.content_type_for(path) - end - end - - # create the directory if it doesn't exist - # Overwritten to avoid ruby 2.7 deprecations - def mkdir!(path, directory_permissions) - options = {} - options[:mode] = directory_permissions if directory_permissions - FileUtils.mkdir_p(File.dirname(path), **options) - end - end -end - -OpenProject::Patches.patch_gem_version "carrierwave", "1.3.4" do - CarrierWave::SanitizedFile.include OpenProject::Patches::CarrierwaveSanitizedFile -end diff --git a/nix/gemset.nix b/nix/gemset.nix index db77431ee4e..9b80c3d84d8 100644 --- a/nix/gemset.nix +++ b/nix/gemset.nix @@ -527,15 +527,15 @@ version = "1.0.25"; }; carrierwave = { - dependencies = ["activemodel" "activesupport" "mime-types" "ssrf_filter"]; + dependencies = ["activemodel" "activesupport" "addressable" "image_processing" "marcel" "mini_mime" "ssrf_filter"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "055i3ybjv9n9hqaazxn3d9ibqhlwh93d4hdlwbpjjfy8qbrz6hiw"; + sha256 = "dy6364hzm3ijfzxgwdi3ny66sc24gyqj1wvsx60zj7xzmy3qsyh1"; type = "gem"; }; - version = "1.3.2"; + version = "2.2.6"; }; carrierwave_direct = { dependencies = ["carrierwave" "fog-aws"]; @@ -1695,10 +1695,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1vhp6lifwvqs2b0a276lj61n86c1l7d1xiswjj2w23f54gl51mpk"; + sha256 = "dhmj4zvnbs3kirgs6s2d933hsds9pim6hf88rk807l1m8km2n091"; type = "gem"; }; - version = "1.0.0"; + version = "1.0.4"; }; messagebird-rest = { groups = ["default" "opf_plugins"]; @@ -3314,10 +3314,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "03f49f54837e407d43ee93ec733a8a94dc1bcf8185647ac61606e63aaedaa0db"; + sha256 = "632vjyxwh673082knymg3j82ml22f2fxw5z2m31h2816q3cm6mw1"; type = "gem"; }; - version = "1.0.8"; + version = "1.3.0"; }; stackprof = { groups = ["development" "test"]; diff --git a/spec/lib/open_project/patches/carrierwave_sanitized_file_spec.rb b/spec/lib/open_project/patches/carrierwave_sanitized_file_spec.rb deleted file mode 100644 index 14e6fb5d0b7..00000000000 --- a/spec/lib/open_project/patches/carrierwave_sanitized_file_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) the OpenProject GmbH -# -# 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-2013 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 COPYRIGHT and LICENSE files for more details. -#++ -require "spec_helper" - -# Adapt the carrierwave sanitized file tests to the content type detector -RSpec.describe OpenProject::Patches::CarrierwaveSanitizedFile do - let(:file) { FileHelpers.mock_uploaded_file(name: "original-filename.txt") } - - it "uses the first one when multiple mime types are given using a semicolon" do - allow(file).to receive(:content_type).and_return("image/png; text/html") - - sanitized_file = CarrierWave::SanitizedFile.new(file) - - expect(sanitized_file.content_type).to eq("image/png") - end - - it "uses the first one when multiple mime types are given using a comma" do - allow(file).to receive(:content_type).and_return("image/png, text/html") - - sanitized_file = CarrierWave::SanitizedFile.new(file) - - expect(sanitized_file.content_type).to eq("image/png") - end - - it "drops content type parameters" do - allow(file).to receive(:content_type).and_return("text/html; charset=utf-8") - - sanitized_file = CarrierWave::SanitizedFile.new(file) - - expect(sanitized_file.content_type).to eq("text/html") - end -end diff --git a/spec/support/shared/with_direct_uploads.rb b/spec/support/shared/with_direct_uploads.rb index 302dd0b5677..144da94d473 100644 --- a/spec/support/shared/with_direct_uploads.rb +++ b/spec/support/shared/with_direct_uploads.rb @@ -172,14 +172,19 @@ RSpec.configure do |config| WithDirectUploads.new(self).before example - class FogAttachment < Attachment - # Remounting the uploader overrides the original file setter taking care of setting, - # among other things, the content type. So we have to restore that original - # method this way. - # We do this in a new, separate class, as to not interfere with any other specs. - alias_method :set_file, :file= - mount_uploader :file, FogFileUploader - alias_method :file=, :set_file + # Only define FogAttachment once. In CW 2.x, mount_uploader uses prepend, + # so re-opening the class and re-mounting would stack prepend modules and + # cause infinite recursion with the alias_method trick below. + unless defined?(FogAttachment) + class FogAttachment < Attachment + # Remounting the uploader overrides the original file setter taking care of setting, + # among other things, the content type. So we have to restore that original + # method this way. + # We do this in a new, separate class, as to not interfere with any other specs. + alias_method :set_file, :file= + mount_uploader :file, FogFileUploader + alias_method :file=, :set_file + end end end