From 887e9af84ffbfdfe1925164947af9892f9f2bbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 11 Jan 2017 23:37:12 +0100 Subject: [PATCH] FEATURE: new 'max_image_megapixels' site setting --- app/models/upload.rb | 15 +++++++++++---- config/locales/server.en.yml | 3 +++ config/site_settings.yml | 4 ++++ spec/fixtures/images/huge.jpg | Bin 0 -> 557056 bytes spec/models/upload_spec.rb | 11 ++++++++++- 5 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 spec/fixtures/images/huge.jpg diff --git a/app/models/upload.rb b/app/models/upload.rb index cf95ec5aa28..d6119abc13c 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -95,6 +95,8 @@ class Upload < ActiveRecord::Base # - image_type ("avatar", "profile_background", "card_background") # - is_attachment_for_group_message (boolean) def self.create_for(user_id, file, filename, filesize, options = {}) + upload = Upload.new + DistributedMutex.synchronize("upload_#{user_id}_#{filename}") do # do some work on images if FileHelper.is_image?(filename) && is_actual_image?(file) @@ -105,13 +107,19 @@ class Upload < ActiveRecord::Base File.write(file.path, doc.to_s) file.rewind else + # ensure image isn't huge + w, h = FastImage.size(file) || [0, 0] + if w * h >= SiteSetting.max_image_megapixels * 1_000_000 + upload.errors.add(:base, I18n.t("upload.images.larger_than_x_megapixels", max_image_megapixels: SiteSetting.max_image_megapixels)) + return upload + end + # fix orientation first fix_image_orientation(file.path) if should_optimize?(file.path) end # retrieve image info - image_info = FastImage.new(file) - w, h = *(image_info.try(:size) || [0, 0]) + w, h = FastImage.size(file) || [0, 0] # default size width, height = ImageSizer.resize(w, h) @@ -214,8 +222,7 @@ class Upload < ActiveRecord::Base # don't optimize GIFs or SVGs return false if path =~ /\.(gif|svg)$/i return true if path !~ /\.png$/i - image_info = FastImage.new(path) rescue nil - w, h = *(image_info.try(:size) || [0, 0]) + w, h = FastImage.size(path) || [0, 0] # don't optimize large PNGs w > 0 && h > 0 && w * h < LARGE_PNG_SIZE end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 808beed3794..6468a337a07 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1213,6 +1213,8 @@ en: authorized_extensions: "A list of file extensions allowed for upload (use '*' to enable all file types)" max_similar_results: "How many similar topics to show above the editor when composing a new topic. Comparison is based on title and body." + max_image_megapixels: "Maximum number of megapixels allowed for an image." + title_prettify: "Prevent common title typos and errors, including all caps, lowercase first character, multiple ! and ?, extra . at end, etc." topic_views_heat_low: "After this many views, the views field is slightly highlighted." @@ -2640,6 +2642,7 @@ en: too_large: "Sorry, the file you are trying to upload is too big (maximum size is %{max_size_kb}KB)." images: too_large: "Sorry, the image you are trying to upload is too big (maximum size is %{max_size_kb}KB), please resize it and try again." + larger_than_x_megapixels: "Sorry, the image you are trying to upload is too large (maximum dimension is %{max_image_megapixels}-megapixels), please resize it and try again." size_not_found: "Sorry, but we couldn't determine the size of the image. Maybe your image is corrupted?" avatar: diff --git a/config/site_settings.yml b/config/site_settings.yml index 4344fab89e5..ae668d64e45 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -699,6 +699,10 @@ files: max_attachment_size_kb: client: true default: 3072 + max_image_megapixels: + default: 40 + min: 5 + max: 100 authorized_extensions: client: true default: 'jpg|jpeg|png|gif' diff --git a/spec/fixtures/images/huge.jpg b/spec/fixtures/images/huge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25f2d5c6fb460b9ee97f1a777594df6feb295089 GIT binary patch literal 557056 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 0 + end + it "fix image orientation" do Upload.expects(:fix_image_orientation).with(image.path) Upload.create_for(user_id, image, image_filename, image_filesize) @@ -62,7 +72,6 @@ describe Upload do it "computes width & height for images" do ImageSizer.expects(:resize) - image.expects(:rewind).times(3) Upload.create_for(user_id, image, image_filename, image_filesize) end