Fix #3917: Uploads: validate file before resizing/distributing.
This commit is contained in:
@@ -66,9 +66,15 @@ class UploadService
|
||||
w, h = calculate_ugoira_dimensions(file.path)
|
||||
yield(w, h)
|
||||
|
||||
else
|
||||
elsif upload.is_image? || upload.is_flash?
|
||||
image_size = ImageSpec.new(file.path)
|
||||
yield(image_size.width, image_size.height)
|
||||
|
||||
elsif upload.file_ext == "bin"
|
||||
yield(0, 0)
|
||||
|
||||
else
|
||||
raise ArgumentError, "unhandled file type (#{upload.file_ext})" # should not happen
|
||||
end
|
||||
end
|
||||
|
||||
@@ -141,6 +147,7 @@ class UploadService
|
||||
upload.image_height = height
|
||||
end
|
||||
|
||||
upload.validate!(:file)
|
||||
upload.tag_string = "#{upload.tag_string} #{Utils.automatic_tags(upload, file)}"
|
||||
|
||||
preview_file, crop_file, sample_file = Utils.generate_resizes(file, upload)
|
||||
|
||||
@@ -3,16 +3,20 @@ require "tmpdir"
|
||||
class Upload < ApplicationRecord
|
||||
class Error < Exception ; end
|
||||
|
||||
class Validator < ActiveModel::Validator
|
||||
class FileValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
if record.new_record?
|
||||
validate_md5_uniqueness(record)
|
||||
validate_video_duration(record)
|
||||
end
|
||||
|
||||
validate_file_ext(record)
|
||||
validate_md5_uniqueness(record)
|
||||
validate_video_duration(record)
|
||||
validate_resolution(record)
|
||||
end
|
||||
|
||||
def validate_file_ext(record)
|
||||
if record.file_ext == "bin"
|
||||
record.errors[:file_ext] << "is invalid (only JPEG, PNG, GIF, SWF, MP4, and WebM files are allowed"
|
||||
end
|
||||
end
|
||||
|
||||
def validate_md5_uniqueness(record)
|
||||
if record.md5.nil?
|
||||
return
|
||||
@@ -36,6 +40,10 @@ class Upload < ApplicationRecord
|
||||
|
||||
if resolution > Danbooru.config.max_image_resolution
|
||||
record.errors[:base] << "image resolution is too large (resolution: #{(resolution / 1_000_000.0).round(1)} megapixels (#{record.image_width}x#{record.image_height}); max: #{Danbooru.config.max_image_resolution / 1_000_000} megapixels)"
|
||||
elsif record.image_width > Danbooru.config.max_image_width
|
||||
record.errors[:image_width] << "is too large (width: #{record.image_width}; max width: #{Danbooru.config.max_image_width})"
|
||||
elsif record.image_height > Danbooru.config.max_image_height
|
||||
record.errors[:image_height] << "is too large (height: #{record.image_height}; max height: #{Danbooru.config.max_image_height})"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -55,12 +63,9 @@ class Upload < ApplicationRecord
|
||||
before_validation :assign_rating_from_tags
|
||||
validate :uploader_is_not_limited, on: :create
|
||||
# validates :source, format: { with: /\Ahttps?/ }, if: ->(record) {record.file.blank?}, on: :create
|
||||
validates :image_height, numericality: { less_than_or_equal_to: Danbooru.config.max_image_height }, allow_nil: true
|
||||
validates :image_width, numericality: { less_than_or_equal_to: Danbooru.config.max_image_width }, allow_nil: true
|
||||
validates :rating, inclusion: { in: %w(q e s) }, allow_nil: true
|
||||
validates :md5, confirmation: true, if: -> (rec) { rec.md5_confirmation.present? }
|
||||
validates :file_ext, format: { with: /jpg|gif|png|swf|webm|mp4|zip/ }, allow_nil: true
|
||||
validates_with Validator
|
||||
validates_with FileValidator, on: :file
|
||||
serialize :context, JSON
|
||||
scope :preprocessed, -> { where(status: "preprocessed") }
|
||||
|
||||
|
||||
@@ -108,9 +108,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
context "for an ugoira" do
|
||||
setup do
|
||||
@file = File.open("test/files/valid_ugoira.zip", "rb")
|
||||
@upload = mock()
|
||||
@upload.stubs(:is_video?).returns(false)
|
||||
@upload.stubs(:is_ugoira?).returns(true)
|
||||
@upload = Upload.new(file_ext: "zip")
|
||||
end
|
||||
|
||||
teardown do
|
||||
@@ -129,8 +127,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
context "for a video" do
|
||||
setup do
|
||||
@file = File.open("test/files/test-300x300.mp4", "rb")
|
||||
@upload = mock()
|
||||
@upload.stubs(:is_video?).returns(true)
|
||||
@upload = Upload.new(file_ext: "mp4")
|
||||
end
|
||||
|
||||
teardown do
|
||||
@@ -148,9 +145,7 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
context "for an image" do
|
||||
setup do
|
||||
@file = File.open("test/files/test.jpg", "rb")
|
||||
@upload = mock()
|
||||
@upload.stubs(:is_video?).returns(false)
|
||||
@upload.stubs(:is_ugoira?).returns(false)
|
||||
@upload = Upload.new(file_ext: "jpg")
|
||||
end
|
||||
|
||||
teardown do
|
||||
@@ -498,15 +493,9 @@ class UploadServiceTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
context "for an invalid content type" do
|
||||
setup do
|
||||
@source = "http://www.example.com"
|
||||
@service = subject.new(source: @source)
|
||||
end
|
||||
|
||||
should "fail" do
|
||||
upload = @service.start!
|
||||
upload.reload
|
||||
assert_match(/error:/, upload.status)
|
||||
upload = subject.new(source: "http://www.example.com").start!
|
||||
assert_match(/\Aerror:.*File ext is invalid/, upload.status)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user