attachment_saver 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +2 -1
- data/attachment_saver.gemspec +2 -7
- data/lib/attachment_saver.rb +0 -1
- data/lib/attachment_saver/version.rb +1 -1
- data/lib/datastores/file_system.rb +1 -1
- data/lib/processors/image.rb +28 -1
- data/lib/processors/image_science.rb +1 -1
- data/lib/processors/mini_magick.rb +2 -2
- data/lib/processors/r_magick.rb +1 -1
- data/test/attachment_saver_test.rb +1 -1
- data/test/file_system_datastore_test.rb +4 -2
- data/test/image_fixtures.rb +8 -0
- data/test/image_processor_test.rb +13 -10
- data/test/image_processor_test_common.rb +12 -2
- data/test/image_science_processor_test.rb +1 -1
- data/test/in_column_datastore_test.rb +2 -2
- data/test/mini_magick_processor_test.rb +1 -1
- data/test/model_test.rb +5 -5
- data/test/rmagick_processor_test.rb +1 -1
- data/test/test_helper.rb +4 -7
- metadata +34 -27
- data/lib/misc/file_size.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e98ac80c02ee411fd7ea5ad5b6c0ea691e9b4e8
|
4
|
+
data.tar.gz: 54a6365fa0959a3f273e7daf4b904ffa7b0fbff7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81e68dc896fe18afa31e7e4573ccdbe9629f6d87f71a57e8a5ae4ac38a0f6c89fde78f38a3e60f3429908e8c685d4c9871cafc248cdfe6917b138b18c41e2a61
|
7
|
+
data.tar.gz: d2942a80062936f13e518a18dddf63e4a5514358fc677e43f7f2a2bcfd325e1c8581fa4b1774dce6bfabc98eece19843646c3a8f071891b947b1fd62b6e4a0bb
|
data/Rakefile
CHANGED
data/attachment_saver.gemspec
CHANGED
@@ -14,18 +14,12 @@ of processing. Errors are carefully handled to minimize the possibility of
|
|
14
14
|
broken uploads leaving incomplete or corrupt data.
|
15
15
|
|
16
16
|
RMagick, MiniMagick, and ImageScience image processors are supported.
|
17
|
-
|
18
|
-
|
19
|
-
Compatibility
|
20
|
-
=============
|
21
|
-
|
22
|
-
Currently tested against Rails 3.2.13 and 3.1.8, on Ruby 1.8.7 and 2.0.0p0.
|
23
|
-
Was also tested compatible with 2.3.14 and 3.0.17.
|
24
17
|
EOF
|
25
18
|
gem.has_rdoc = false
|
26
19
|
gem.author = "Will Bryant"
|
27
20
|
gem.email = "will.bryant@gmail.com"
|
28
21
|
gem.homepage = "http://github.com/willbryant/attachment_saver"
|
22
|
+
gem.license = 'MIT'
|
29
23
|
|
30
24
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
31
25
|
gem.files = `git ls-files`.split("\n")
|
@@ -33,6 +27,7 @@ EOF
|
|
33
27
|
gem.require_path = "lib"
|
34
28
|
|
35
29
|
gem.add_dependency "activerecord"
|
30
|
+
gem.add_dependency "mimemagic"
|
36
31
|
gem.add_development_dependency "rake"
|
37
32
|
gem.add_development_dependency "image_science"
|
38
33
|
gem.add_development_dependency "rmagick"
|
data/lib/attachment_saver.rb
CHANGED
data/lib/processors/image.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'attachment_saver_errors'
|
2
|
+
require 'mimemagic'
|
2
3
|
|
3
4
|
class ImageProcessorError < AttachmentProcessorError; end
|
4
5
|
|
@@ -6,14 +7,40 @@ module AttachmentSaver
|
|
6
7
|
module Processors
|
7
8
|
# shared code for all image processors
|
8
9
|
module Image
|
10
|
+
DEFAULT_VALID_IMAGE_TYPES = %w(image/jpeg image/png image/gif).freeze
|
11
|
+
|
9
12
|
def image?
|
10
13
|
return false if content_type.blank?
|
11
14
|
parts = content_type.split(/\//)
|
12
15
|
parts.size == 2 && parts.first.strip == 'image'
|
13
16
|
end
|
17
|
+
|
18
|
+
def valid_image_type
|
19
|
+
valid_image_types = self.class.attachment_options[:valid_image_types] || DEFAULT_VALID_IMAGE_TYPES
|
20
|
+
|
21
|
+
uploaded_file.rewind
|
22
|
+
magic = MimeMagic.by_magic(uploaded_file)
|
23
|
+
|
24
|
+
if magic.nil?
|
25
|
+
# if it doesn't look like an image, make sure it's not labelled as an image
|
26
|
+
self.content_type = 'application/octet-stream' if image? || content_type.nil?
|
27
|
+
elsif !valid_image_types.include?(magic.type)
|
28
|
+
# overwrite the content type given by the untrusted client with the real content type; it may get refined later by the image processor
|
29
|
+
self.content_type = magic.type
|
30
|
+
else
|
31
|
+
# seems legit
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
|
35
|
+
errors.add(:content_type, "is invalid") if respond_to?(:errors)
|
36
|
+
false
|
37
|
+
end
|
14
38
|
|
15
39
|
def before_validate_attachment
|
16
|
-
|
40
|
+
unless uploaded_file.nil? || derived_image?
|
41
|
+
return false unless valid_image_type
|
42
|
+
examine_image
|
43
|
+
end
|
17
44
|
rescue ImageProcessorError
|
18
45
|
# we examine all files, regardless of whether the client browser labelled them an
|
19
46
|
# image, because they may be an image with the wrong extension or content type.
|
@@ -19,7 +19,7 @@ module AttachmentSaver
|
|
19
19
|
::ImageScience.with_image_attributes(filename) {|image| block.call(image)}
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def examine_image
|
23
23
|
with_image_attributes(uploaded_file_path) do |original_image|
|
24
24
|
self.width = original_image.width if respond_to?(:width)
|
25
25
|
self.height = original_image.height if respond_to?(:height)
|
@@ -28,7 +28,7 @@ module AttachmentSaver
|
|
28
28
|
with_image(filename, &block)
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
31
|
+
def examine_image
|
32
32
|
with_image_attributes(uploaded_file_path) do |original_image|
|
33
33
|
self.content_type = original_image.mime_type unless self.class.attachment_options[:keep_content_type] || original_image.mime_type.blank?
|
34
34
|
self.file_extension = original_image.file_type_extension unless self.class.attachment_options[:keep_file_extension] || original_image.file_type_extension.blank?
|
@@ -93,7 +93,7 @@ module AttachmentSaver
|
|
93
93
|
left = (width - new_width)/2
|
94
94
|
right = (height - new_height)/2
|
95
95
|
image = dup
|
96
|
-
image
|
96
|
+
image.crop("#{new_width}x#{new_height}+#{left}+#{right}", "+repage")
|
97
97
|
image.extend Operations
|
98
98
|
block.call(image)
|
99
99
|
end
|
data/lib/processors/r_magick.rb
CHANGED
@@ -23,7 +23,7 @@ module AttachmentSaver
|
|
23
23
|
block.call(image.extend(Operations))
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
26
|
+
def examine_image
|
27
27
|
with_image_attributes(uploaded_file_path) do |original_image|
|
28
28
|
self.width = original_image.width if respond_to?(:width)
|
29
29
|
self.height = original_image.height if respond_to?(:height)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
2
|
require 'attachment_saver'
|
3
3
|
|
4
|
-
class AttachmentSaverTest <
|
4
|
+
class AttachmentSaverTest < ActiveSupport::TestCase
|
5
5
|
def test_split_filename
|
6
6
|
assert_equal ['a', nil], AttachmentSaver::split_filename('a')
|
7
7
|
assert_equal ['a', ''], AttachmentSaver::split_filename('a.')
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
-
require 'mocha'
|
2
|
+
require 'mocha/test_unit'
|
3
3
|
require 'datastores/file_system'
|
4
4
|
|
5
|
-
class FileSystemDatastoreTest <
|
5
|
+
class FileSystemDatastoreTest < ActiveSupport::TestCase
|
6
6
|
attr_accessor :storage_key, :original_filename, :content_type
|
7
7
|
|
8
8
|
DEFAULT_ATTACHMENT_OPTIONS = {:storage_directory => File.join(TEST_TEMP_DIR, 'fs_store_test'),
|
@@ -151,6 +151,8 @@ class FileSystemDatastoreTest < Test::Unit::TestCase
|
|
151
151
|
save_attachment_to_test(data)
|
152
152
|
save_test_independent_files(file, data)
|
153
153
|
end
|
154
|
+
ensure
|
155
|
+
FileUtils.unstub(:ln)
|
154
156
|
end
|
155
157
|
|
156
158
|
|
data/test/image_fixtures.rb
CHANGED
@@ -60,6 +60,14 @@ class ImageFixtures
|
|
60
60
|
:expected_extension => 'js' }
|
61
61
|
end
|
62
62
|
|
63
|
+
def self.exploit_file
|
64
|
+
{ :path => fixture_path('ssrf.png'), # actually a .mvg file
|
65
|
+
:content_type => 'image/png',
|
66
|
+
:original_filename => 'ssrf.png',
|
67
|
+
:expected_content_type => 'application/octet-stream',
|
68
|
+
:expected_extension => 'mvg' }
|
69
|
+
end
|
70
|
+
|
63
71
|
def self.all_readable
|
64
72
|
[valid, wrong_extension, no_extension, empty_extension]
|
65
73
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
-
require 'mocha'
|
2
|
+
require 'mocha/test_unit'
|
3
3
|
require 'processors/image'
|
4
4
|
require File.expand_path(File.join(File.dirname(__FILE__), 'image_operations'))
|
5
5
|
|
6
|
-
class ImageProcessorTest <
|
6
|
+
class ImageProcessorTest < ActiveSupport::TestCase
|
7
7
|
class SomeModel
|
8
8
|
include AttachmentSaver::Processors::Image
|
9
9
|
|
@@ -16,6 +16,7 @@ class ImageProcessorTest < Test::Unit::TestCase
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_image?
|
19
|
+
SomeModel.attachment_options = {}
|
19
20
|
[nil, '', '/', 'foo', 'foo/' '/bar', 'text/plain', 'x-image/invalid', 'image-x/invalid'].each do |mime|
|
20
21
|
assert_equal false, SomeModel.new(mime).image?
|
21
22
|
end
|
@@ -36,30 +37,32 @@ class ImageProcessorTest < Test::Unit::TestCase
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def test_before_validate_attachment
|
39
|
-
|
40
|
+
SomeModel.attachment_options = {}
|
41
|
+
model_without_upload = SomeModel.new('application/octet-stream') # note the content type doesn't have to be an image for examine_image to be called, since examine_image is supposed to fix up incorrect client-supplied content-types
|
40
42
|
model_without_upload.expects(:uploaded_file).times(1).returns(nil)
|
41
|
-
model_without_upload.expects(:
|
43
|
+
model_without_upload.expects(:examine_image).times(0)
|
42
44
|
model_without_upload.before_validate_attachment
|
43
45
|
|
44
46
|
model_with_upload = SomeModel.new('application/octet-stream')
|
45
|
-
model_with_upload.expects(:uploaded_file).
|
46
|
-
model_with_upload.expects(:
|
47
|
+
model_with_upload.expects(:uploaded_file).at_least(:once).returns(StringIO.new('dummy'))
|
48
|
+
model_with_upload.expects(:examine_image).times(1)
|
47
49
|
model_with_upload.before_validate_attachment
|
48
50
|
|
49
51
|
model_with_non_image_upload = SomeModel.new('text/plain')
|
50
|
-
model_with_non_image_upload.expects(:uploaded_file).
|
51
|
-
model_with_non_image_upload.expects(:
|
52
|
+
model_with_non_image_upload.expects(:uploaded_file).at_least(:once).returns(StringIO.new('dummy'))
|
53
|
+
model_with_non_image_upload.expects(:examine_image).times(1).raises(ImageProcessorError)
|
52
54
|
model_with_non_image_upload.before_validate_attachment
|
53
55
|
assert_equal 'text/plain', model_with_non_image_upload.content_type
|
54
56
|
|
55
57
|
model_with_mislabelled_non_image_upload = SomeModel.new('image/png')
|
56
|
-
model_with_mislabelled_non_image_upload.expects(:uploaded_file).
|
57
|
-
model_with_mislabelled_non_image_upload.expects(:
|
58
|
+
model_with_mislabelled_non_image_upload.expects(:uploaded_file).at_least(:once).returns(StringIO.new('dummy'))
|
59
|
+
model_with_mislabelled_non_image_upload.expects(:examine_image).times(1).raises(ImageProcessorError)
|
58
60
|
model_with_mislabelled_non_image_upload.before_validate_attachment
|
59
61
|
assert_equal 'application/octet-stream', model_with_mislabelled_non_image_upload.content_type
|
60
62
|
end
|
61
63
|
|
62
64
|
def test_from_geometry_string
|
65
|
+
SomeModel.attachment_options = {}
|
63
66
|
ImageOperations::geometry_strings.each do |geometry, expected_result|
|
64
67
|
assert_equal expected_result, AttachmentSaver::Processors::Image.from_geometry_string(geometry), "geometry parse of #{geometry} produced incorrect results"
|
65
68
|
end
|
@@ -8,6 +8,7 @@ module ImageProcessorTestModel
|
|
8
8
|
|
9
9
|
def self.included(base)
|
10
10
|
base.cattr_accessor :attachment_options
|
11
|
+
base.attachment_options = {}
|
11
12
|
end
|
12
13
|
|
13
14
|
def initialize(uploaded_data)
|
@@ -36,7 +37,7 @@ module ImageProcessorTests
|
|
36
37
|
model = processor_model.new(File.open(fixture[:path], 'rb'))
|
37
38
|
model.content_type = fixture[:content_type]
|
38
39
|
model.original_filename = fixture[:original_filename]
|
39
|
-
model.
|
40
|
+
model.examine_image
|
40
41
|
assert_equal fixture[:expected_content_type], model.content_type
|
41
42
|
assert_equal fixture[:width], model.width
|
42
43
|
assert_equal fixture[:height], model.height
|
@@ -50,7 +51,7 @@ module ImageProcessorTests
|
|
50
51
|
ImageFixtures.all_unreadable.each do |fixture|
|
51
52
|
model = processor_model.new(File.open(fixture[:path], 'rb'))
|
52
53
|
model.content_type = fixture[:content_type]
|
53
|
-
assert_raises(processor_exception) { model.
|
54
|
+
assert_raises(processor_exception) { model.examine_image }
|
54
55
|
assert_equal fixture[:expected_content_type], model.content_type
|
55
56
|
assert_equal nil, model.width
|
56
57
|
assert_equal nil, model.height
|
@@ -61,6 +62,15 @@ module ImageProcessorTests
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
65
|
+
def test_image_exploits
|
66
|
+
processor_model.attachment_options = {:valid_image_types => %w(image/png image/jpeg)}
|
67
|
+
|
68
|
+
model = processor_model.new(File.open(ImageFixtures.fixture_path('ssrf.png'), 'rb')) # actually a .mvg file
|
69
|
+
model.expects(:examine_attachment).times(0) # don't invoke the potentially vulnerable image processor code
|
70
|
+
model.before_validate_attachment
|
71
|
+
assert_not_equal 'image/png', model.content_type
|
72
|
+
end
|
73
|
+
|
64
74
|
def test_derived_attributes_from_valid
|
65
75
|
processor_model.attachment_options = {:formats => ImageOperations.resize_operations}
|
66
76
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'image_processor_test_common'))
|
2
2
|
require 'processors/image_science'
|
3
3
|
|
4
|
-
class ImageScienceProcessorTest <
|
4
|
+
class ImageScienceProcessorTest < ActiveSupport::TestCase
|
5
5
|
class ImageScienceTestModel
|
6
6
|
include AttachmentSaver::InstanceMethods
|
7
7
|
include AttachmentSaver::Processors::ImageScience
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
-
require 'mocha'
|
2
|
+
require 'mocha/test_unit'
|
3
3
|
require 'datastores/in_column'
|
4
4
|
|
5
|
-
class InColumnDatastoreTest <
|
5
|
+
class InColumnDatastoreTest < ActiveSupport::TestCase
|
6
6
|
attr_accessor :data, :original_filename, :content_type
|
7
7
|
|
8
8
|
DEFAULT_ATTACHMENT_OPTIONS = {}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'image_processor_test_common'))
|
2
2
|
require 'processors/mini_magick'
|
3
3
|
|
4
|
-
class MiniMagickProcessorTest <
|
4
|
+
class MiniMagickProcessorTest < ActiveSupport::TestCase
|
5
5
|
class MiniMagickTestModel
|
6
6
|
include AttachmentSaver::InstanceMethods
|
7
7
|
include AttachmentSaver::Processors::MiniMagick
|
data/test/model_test.rb
CHANGED
@@ -28,7 +28,7 @@ class Unprocessed < ActiveRecord::Base
|
|
28
28
|
end
|
29
29
|
|
30
30
|
class LoadedImage < ActiveRecord::Base
|
31
|
-
|
31
|
+
self.table_name = 'images'
|
32
32
|
saves_attachment :processor => 'image_science' # don't create any derived images, but still process the image to get the attributes
|
33
33
|
end
|
34
34
|
|
@@ -38,21 +38,21 @@ class AllInOneTableImages < ActiveRecord::Base
|
|
38
38
|
end
|
39
39
|
|
40
40
|
class ImageScienceImage < ActiveRecord::Base
|
41
|
-
|
41
|
+
self.table_name = 'images'
|
42
42
|
saves_attachment :processor => 'ImageScience', :formats => {:small => '200x200'}
|
43
43
|
end
|
44
44
|
|
45
45
|
class RMagickImage < ActiveRecord::Base
|
46
|
-
|
46
|
+
self.table_name = 'images'
|
47
47
|
saves_attachment :processor => 'RMagick', :formats => {:small => '200x200'}
|
48
48
|
end
|
49
49
|
|
50
50
|
class MiniMagickImage < ActiveRecord::Base
|
51
|
-
|
51
|
+
self.table_name = 'images'
|
52
52
|
saves_attachment :processor => 'RMagick', :formats => {:small => '200x200'}
|
53
53
|
end
|
54
54
|
|
55
|
-
class ModelTest <
|
55
|
+
class ModelTest < ActiveSupport::TestCase
|
56
56
|
module ValidUploadedFileAttributes
|
57
57
|
def fixture=(value)
|
58
58
|
@fixture = value
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'image_processor_test_common'))
|
2
2
|
require 'processors/r_magick'
|
3
3
|
|
4
|
-
class RMagickProcessorTest <
|
4
|
+
class RMagickProcessorTest < ActiveSupport::TestCase
|
5
5
|
class RMagickTestModel
|
6
6
|
include AttachmentSaver::InstanceMethods
|
7
7
|
include AttachmentSaver::Processors::RMagick
|
data/test/test_helper.rb
CHANGED
@@ -7,17 +7,16 @@ end
|
|
7
7
|
gem 'activesupport', ENV['RAILS_VERSION']
|
8
8
|
gem 'activerecord', ENV['RAILS_VERSION']
|
9
9
|
|
10
|
-
require '
|
10
|
+
require 'minitest/autorun'
|
11
11
|
require 'active_support'
|
12
12
|
require 'active_support/test_case'
|
13
13
|
require 'active_record'
|
14
14
|
require 'active_record/fixtures'
|
15
15
|
|
16
16
|
begin
|
17
|
-
require '
|
18
|
-
Debugger.start
|
17
|
+
require 'byebug'
|
19
18
|
rescue LoadError
|
20
|
-
#
|
19
|
+
# no debugging for you
|
21
20
|
end
|
22
21
|
|
23
22
|
RAILS_ROOT = File.dirname(__FILE__)
|
@@ -42,8 +41,6 @@ load(File.join(File.dirname(__FILE__), "/schema.rb"))
|
|
42
41
|
|
43
42
|
require File.expand_path(File.join(File.dirname(__FILE__), '../init')) # load the plugin
|
44
43
|
|
45
|
-
at_exit do
|
44
|
+
at_exit do
|
46
45
|
FileUtils.rm_rf(File.join(File.dirname(__FILE__), 'tmp'))
|
47
46
|
end
|
48
|
-
|
49
|
-
require 'test/unit'
|
metadata
CHANGED
@@ -1,97 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attachment_saver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Will Bryant
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mimemagic
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
|
-
- -
|
45
|
+
- - ">="
|
32
46
|
- !ruby/object:Gem::Version
|
33
47
|
version: '0'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- -
|
52
|
+
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: image_science
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- -
|
59
|
+
- - ">="
|
46
60
|
- !ruby/object:Gem::Version
|
47
61
|
version: '0'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- -
|
66
|
+
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rmagick
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- -
|
73
|
+
- - ">="
|
60
74
|
- !ruby/object:Gem::Version
|
61
75
|
version: '0'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- -
|
80
|
+
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: mini_magick
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- -
|
87
|
+
- - ">="
|
74
88
|
- !ruby/object:Gem::Version
|
75
89
|
version: '0'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- -
|
94
|
+
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: sqlite3
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- -
|
101
|
+
- - ">="
|
88
102
|
- !ruby/object:Gem::Version
|
89
103
|
version: '0'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
|
-
- -
|
108
|
+
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
111
|
description: |
|
@@ -103,19 +117,12 @@ description: |
|
|
103
117
|
broken uploads leaving incomplete or corrupt data.
|
104
118
|
|
105
119
|
RMagick, MiniMagick, and ImageScience image processors are supported.
|
106
|
-
|
107
|
-
|
108
|
-
Compatibility
|
109
|
-
=============
|
110
|
-
|
111
|
-
Currently tested against Rails 3.2.13 and 3.1.8, on Ruby 1.8.7 and 2.0.0p0.
|
112
|
-
Was also tested compatible with 2.3.14 and 3.0.17.
|
113
120
|
email: will.bryant@gmail.com
|
114
121
|
executables: []
|
115
122
|
extensions: []
|
116
123
|
extra_rdoc_files: []
|
117
124
|
files:
|
118
|
-
- .gitignore
|
125
|
+
- ".gitignore"
|
119
126
|
- MIT-LICENSE
|
120
127
|
- README
|
121
128
|
- Rakefile
|
@@ -127,7 +134,6 @@ files:
|
|
127
134
|
- lib/datastores/file_system.rb
|
128
135
|
- lib/datastores/in_column.rb
|
129
136
|
- lib/misc/extended_tempfile.rb
|
130
|
-
- lib/misc/file_size.rb
|
131
137
|
- lib/misc/image_science_extensions.rb
|
132
138
|
- lib/misc/mini_magick_extensions.rb
|
133
139
|
- lib/processors/image.rb
|
@@ -156,7 +162,8 @@ files:
|
|
156
162
|
- test/schema.rb
|
157
163
|
- test/test_helper.rb
|
158
164
|
homepage: http://github.com/willbryant/attachment_saver
|
159
|
-
licenses:
|
165
|
+
licenses:
|
166
|
+
- MIT
|
160
167
|
metadata: {}
|
161
168
|
post_install_message:
|
162
169
|
rdoc_options: []
|
@@ -164,17 +171,17 @@ require_paths:
|
|
164
171
|
- lib
|
165
172
|
required_ruby_version: !ruby/object:Gem::Requirement
|
166
173
|
requirements:
|
167
|
-
- -
|
174
|
+
- - ">="
|
168
175
|
- !ruby/object:Gem::Version
|
169
176
|
version: '0'
|
170
177
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
178
|
requirements:
|
172
|
-
- -
|
179
|
+
- - ">="
|
173
180
|
- !ruby/object:Gem::Version
|
174
181
|
version: '0'
|
175
182
|
requirements: []
|
176
183
|
rubyforge_project:
|
177
|
-
rubygems_version: 2.
|
184
|
+
rubygems_version: 2.2.5
|
178
185
|
signing_key:
|
179
186
|
specification_version: 4
|
180
187
|
summary: Saves attachments in files, models, or columns.
|