paperclip 3.5.4 → 4.3.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +0 -6
- data/.hound.yml +1066 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +11 -17
- data/Appraisals +6 -14
- data/CONTRIBUTING.md +13 -8
- data/Gemfile +16 -3
- data/LICENSE +1 -3
- data/NEWS +167 -49
- data/README.md +294 -75
- data/RELEASING.md +17 -0
- data/Rakefile +6 -8
- data/features/basic_integration.feature +24 -6
- data/features/step_definitions/attachment_steps.rb +30 -22
- data/features/step_definitions/html_steps.rb +2 -2
- data/features/step_definitions/rails_steps.rb +44 -14
- data/features/step_definitions/web_steps.rb +1 -103
- data/features/support/env.rb +2 -2
- data/features/support/file_helpers.rb +2 -2
- data/features/support/fixtures/gemfile.txt +1 -1
- data/features/support/rails.rb +2 -1
- data/gemfiles/3.2.gemfile +14 -6
- data/gemfiles/4.1.gemfile +19 -0
- data/gemfiles/4.2.gemfile +19 -0
- data/lib/generators/paperclip/paperclip_generator.rb +0 -2
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
- data/lib/paperclip/attachment.rb +132 -38
- data/lib/paperclip/attachment_registry.rb +1 -1
- data/lib/paperclip/callbacks.rb +11 -1
- data/lib/paperclip/content_type_detector.rb +25 -22
- data/lib/paperclip/deprecations.rb +42 -0
- data/lib/paperclip/errors.rb +5 -0
- data/lib/paperclip/file_command_content_type_detector.rb +6 -8
- data/lib/paperclip/geometry_detector_factory.rb +3 -1
- data/lib/paperclip/geometry_parser_factory.rb +1 -1
- data/lib/paperclip/has_attached_file.rb +10 -0
- data/lib/paperclip/interpolations/plural_cache.rb +6 -5
- data/lib/paperclip/interpolations.rb +25 -12
- data/lib/paperclip/io_adapters/abstract_adapter.rb +3 -1
- data/lib/paperclip/io_adapters/attachment_adapter.rb +4 -4
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +5 -10
- data/lib/paperclip/io_adapters/stringio_adapter.rb +6 -10
- data/lib/paperclip/io_adapters/uri_adapter.rb +30 -11
- data/lib/paperclip/locales/de.yml +18 -0
- data/lib/paperclip/locales/en.yml +1 -0
- data/lib/paperclip/locales/es.yml +18 -0
- data/lib/paperclip/locales/ja.yml +18 -0
- data/lib/paperclip/locales/pt-BR.yml +18 -0
- data/lib/paperclip/locales/zh-CN.yml +18 -0
- data/lib/paperclip/locales/zh-HK.yml +18 -0
- data/lib/paperclip/locales/zh-TW.yml +18 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +2 -1
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +2 -1
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +2 -1
- data/lib/paperclip/media_type_spoof_detector.rb +89 -0
- data/lib/paperclip/processor.rb +0 -37
- data/lib/paperclip/processor_helpers.rb +50 -0
- data/lib/paperclip/rails_environment.rb +25 -0
- data/lib/paperclip/schema.rb +10 -2
- data/lib/paperclip/storage/filesystem.rb +1 -1
- data/lib/paperclip/storage/fog.rb +18 -7
- data/lib/paperclip/storage/s3.rb +53 -22
- data/lib/paperclip/style.rb +8 -2
- data/lib/paperclip/tempfile_factory.rb +5 -1
- data/lib/paperclip/thumbnail.rb +12 -10
- data/lib/paperclip/url_generator.rb +11 -3
- data/lib/paperclip/validators/attachment_content_type_validator.rb +4 -0
- data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
- data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
- data/lib/paperclip/validators/attachment_presence_validator.rb +4 -0
- data/lib/paperclip/validators/attachment_size_validator.rb +11 -3
- data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
- data/lib/paperclip/validators.rb +10 -3
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +26 -8
- data/lib/tasks/paperclip.rake +17 -2
- data/paperclip.gemspec +16 -14
- data/shoulda_macros/paperclip.rb +0 -1
- data/spec/paperclip/attachment_definitions_spec.rb +13 -0
- data/{test/attachment_processing_test.rb → spec/paperclip/attachment_processing_spec.rb} +20 -21
- data/spec/paperclip/attachment_registry_spec.rb +130 -0
- data/{test/attachment_test.rb → spec/paperclip/attachment_spec.rb} +438 -397
- data/{test/content_type_detector_test.rb → spec/paperclip/content_type_detector_spec.rb} +16 -19
- data/spec/paperclip/deprecations_spec.rb +65 -0
- data/{test/file_command_content_type_detector_test.rb → spec/paperclip/file_command_content_type_detector_spec.rb} +5 -6
- data/spec/paperclip/filename_cleaner_spec.rb +14 -0
- data/spec/paperclip/geometry_detector_spec.rb +39 -0
- data/{test/geometry_parser_test.rb → spec/paperclip/geometry_parser_spec.rb} +27 -27
- data/{test/geometry_test.rb → spec/paperclip/geometry_spec.rb} +50 -52
- data/spec/paperclip/glue_spec.rb +44 -0
- data/{test/has_attached_file_test.rb → spec/paperclip/has_attached_file_spec.rb} +45 -28
- data/{test/integration_test.rb → spec/paperclip/integration_spec.rb} +134 -126
- data/{test/interpolations_test.rb → spec/paperclip/interpolations_spec.rb} +70 -46
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
- data/{test/io_adapters/attachment_adapter_test.rb → spec/paperclip/io_adapters/attachment_adapter_spec.rb} +27 -29
- data/{test/io_adapters/data_uri_adapter_test.rb → spec/paperclip/io_adapters/data_uri_adapter_spec.rb} +26 -17
- data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
- data/{test/io_adapters/file_adapter_test.rb → spec/paperclip/io_adapters/file_adapter_spec.rb} +36 -40
- data/{test/io_adapters/http_url_proxy_adapter_test.rb → spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb} +31 -29
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
- data/{test/io_adapters/nil_adapter_test.rb → spec/paperclip/io_adapters/nil_adapter_spec.rb} +7 -7
- data/{test/io_adapters/registry_test.rb → spec/paperclip/io_adapters/registry_spec.rb} +10 -7
- data/{test/io_adapters/stringio_adapter_test.rb → spec/paperclip/io_adapters/stringio_adapter_spec.rb} +20 -17
- data/{test/io_adapters/uploaded_file_adapter_test.rb → spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb} +41 -41
- data/{test/io_adapters/uri_adapter_test.rb → spec/paperclip/io_adapters/uri_adapter_spec.rb} +53 -28
- data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +99 -0
- data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
- data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
- data/spec/paperclip/media_type_spoof_detector_spec.rb +79 -0
- data/spec/paperclip/meta_class_spec.rb +30 -0
- data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
- data/{test/paperclip_test.rb → spec/paperclip/paperclip_spec.rb} +53 -48
- data/spec/paperclip/plural_cache_spec.rb +37 -0
- data/spec/paperclip/processor_helpers_spec.rb +57 -0
- data/{test/processor_test.rb → spec/paperclip/processor_spec.rb} +5 -5
- data/spec/paperclip/rails_environment_spec.rb +33 -0
- data/{test/rake_test.rb → spec/paperclip/rake_spec.rb} +15 -15
- data/spec/paperclip/schema_spec.rb +248 -0
- data/{test/storage/filesystem_test.rb → spec/paperclip/storage/filesystem_spec.rb} +18 -18
- data/spec/paperclip/storage/fog_spec.rb +535 -0
- data/spec/paperclip/storage/s3_live_spec.rb +182 -0
- data/spec/paperclip/storage/s3_spec.rb +1526 -0
- data/spec/paperclip/style_spec.rb +255 -0
- data/spec/paperclip/tempfile_factory_spec.rb +33 -0
- data/{test/thumbnail_test.rb → spec/paperclip/thumbnail_spec.rb} +123 -107
- data/spec/paperclip/url_generator_spec.rb +211 -0
- data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
- data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
- data/{test/validators/attachment_presence_validator_test.rb → spec/paperclip/validators/attachment_presence_validator_spec.rb} +20 -20
- data/{test/validators/attachment_size_validator_test.rb → spec/paperclip/validators/attachment_size_validator_spec.rb} +65 -58
- data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
- data/spec/paperclip/validators_spec.rb +164 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/assertions.rb +71 -0
- data/spec/support/deprecations.rb +9 -0
- data/spec/support/fake_model.rb +25 -0
- data/spec/support/fake_rails.rb +12 -0
- data/spec/support/fixtures/empty.html +1 -0
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/fixtures/spaced file.jpg +0 -0
- data/spec/support/matchers/accept.rb +5 -0
- data/spec/support/matchers/exist.rb +5 -0
- data/spec/support/matchers/have_column.rb +23 -0
- data/spec/support/model_reconstruction.rb +60 -0
- data/spec/support/rails_helpers.rb +7 -0
- data/spec/support/test_data.rb +13 -0
- data/spec/support/version_helper.rb +9 -0
- metadata +334 -219
- data/RUNNING_TESTS.md +0 -4
- data/gemfiles/3.0.gemfile +0 -11
- data/gemfiles/3.1.gemfile +0 -11
- data/gemfiles/4.0.gemfile +0 -11
- data/test/attachment_definitions_test.rb +0 -12
- data/test/attachment_registry_test.rb +0 -88
- data/test/filename_cleaner_test.rb +0 -14
- data/test/generator_test.rb +0 -84
- data/test/geometry_detector_test.rb +0 -24
- data/test/helper.rb +0 -232
- data/test/io_adapters/abstract_adapter_test.rb +0 -58
- data/test/io_adapters/empty_string_adapter_test.rb +0 -18
- data/test/io_adapters/identity_adapter_test.rb +0 -8
- data/test/matchers/have_attached_file_matcher_test.rb +0 -24
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +0 -110
- data/test/matchers/validate_attachment_presence_matcher_test.rb +0 -69
- data/test/matchers/validate_attachment_size_matcher_test.rb +0 -86
- data/test/meta_class_test.rb +0 -32
- data/test/paperclip_missing_attachment_styles_test.rb +0 -90
- data/test/plural_cache_test.rb +0 -36
- data/test/schema_test.rb +0 -200
- data/test/storage/fog_test.rb +0 -473
- data/test/storage/s3_live_test.rb +0 -179
- data/test/storage/s3_test.rb +0 -1356
- data/test/style_test.rb +0 -213
- data/test/support/mock_model.rb +0 -2
- data/test/tempfile_factory_test.rb +0 -17
- data/test/url_generator_test.rb +0 -187
- data/test/validators/attachment_content_type_validator_test.rb +0 -324
- data/test/validators_test.rb +0 -61
- /data/{test → spec}/database.yml +0 -0
- /data/{test → spec/support}/fixtures/12k.png +0 -0
- /data/{test → spec/support}/fixtures/50x50.png +0 -0
- /data/{test → spec/support}/fixtures/5k.png +0 -0
- /data/{test → spec/support}/fixtures/animated +0 -0
- /data/{test → spec/support}/fixtures/animated.gif +0 -0
- /data/{test → spec/support}/fixtures/animated.unknown +0 -0
- /data/{test → spec/support}/fixtures/bad.png +0 -0
- /data/{test → spec/support}/fixtures/fog.yml +0 -0
- /data/{test → spec/support}/fixtures/rotated.jpg +0 -0
- /data/{test → spec/support}/fixtures/s3.yml +0 -0
- /data/{test → spec/support}/fixtures/spaced file.png +0 -0
- /data/{test → spec/support}/fixtures/text.txt +0 -0
- /data/{test → spec/support}/fixtures/twopage.pdf +0 -0
- /data/{test → spec/support}/fixtures/uppercase.PNG +0 -0
- /data/{test → spec}/support/mock_attachment.rb +0 -0
- /data/{test → spec}/support/mock_interpolator.rb +0 -0
- /data/{test → spec}/support/mock_url_generator_builder.rb +0 -0
@@ -20,11 +20,11 @@ module Paperclip
|
|
20
20
|
@size = @tempfile.size || @target.size
|
21
21
|
end
|
22
22
|
|
23
|
-
def copy_to_tempfile(
|
24
|
-
if
|
25
|
-
|
23
|
+
def copy_to_tempfile(source)
|
24
|
+
if source.staged?
|
25
|
+
FileUtils.cp(source.staged_path(@style), destination.path)
|
26
26
|
else
|
27
|
-
|
27
|
+
source.copy_to_local_file(@style, destination.path)
|
28
28
|
end
|
29
29
|
destination
|
30
30
|
end
|
@@ -1,22 +1,17 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class DataUriAdapter < StringioAdapter
|
3
3
|
|
4
|
-
REGEXP = /\Adata:([-\w]+\/[-\w
|
4
|
+
REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m
|
5
5
|
|
6
6
|
def initialize(target_uri)
|
7
|
-
|
8
|
-
cache_current_values
|
9
|
-
@tempfile = copy_to_tempfile
|
7
|
+
super(extract_target(target_uri))
|
10
8
|
end
|
11
9
|
|
12
10
|
private
|
13
11
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
@content_type = data_uri_parts[1] || 'text/plain'
|
18
|
-
@target = StringIO.new(Base64.decode64(data_uri_parts[2] || ''))
|
19
|
-
@size = @target.size
|
12
|
+
def extract_target(uri)
|
13
|
+
data_uri_parts = uri.match(REGEXP) || []
|
14
|
+
StringIO.new(Base64.decode64(data_uri_parts[2] || ''))
|
20
15
|
end
|
21
16
|
|
22
17
|
end
|
@@ -3,7 +3,6 @@ module Paperclip
|
|
3
3
|
def initialize(target)
|
4
4
|
@target = target
|
5
5
|
cache_current_values
|
6
|
-
@tempfile = copy_to_tempfile
|
7
6
|
end
|
8
7
|
|
9
8
|
attr_writer :content_type
|
@@ -11,18 +10,15 @@ module Paperclip
|
|
11
10
|
private
|
12
11
|
|
13
12
|
def cache_current_values
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@content_type = @target.content_type if @target.respond_to?(:content_type)
|
19
|
-
@content_type ||= "text/plain"
|
20
|
-
|
13
|
+
self.original_filename = @target.original_filename if @target.respond_to?(:original_filename)
|
14
|
+
self.original_filename ||= "data"
|
15
|
+
@tempfile = copy_to_tempfile(@target)
|
16
|
+
@content_type = ContentTypeDetector.new(@tempfile.path).detect
|
21
17
|
@size = @target.size
|
22
18
|
end
|
23
19
|
|
24
|
-
def copy_to_tempfile
|
25
|
-
while data =
|
20
|
+
def copy_to_tempfile(source)
|
21
|
+
while data = source.read(16*1024)
|
26
22
|
destination.write(data)
|
27
23
|
end
|
28
24
|
destination.rewind
|
@@ -2,6 +2,8 @@ require 'open-uri'
|
|
2
2
|
|
3
3
|
module Paperclip
|
4
4
|
class UriAdapter < AbstractAdapter
|
5
|
+
attr_writer :content_type
|
6
|
+
|
5
7
|
def initialize(target)
|
6
8
|
@target = target
|
7
9
|
@content = download_content
|
@@ -9,23 +11,40 @@ module Paperclip
|
|
9
11
|
@tempfile = copy_to_tempfile(@content)
|
10
12
|
end
|
11
13
|
|
12
|
-
attr_writer :content_type
|
13
|
-
|
14
14
|
private
|
15
15
|
|
16
|
-
def
|
17
|
-
|
16
|
+
def cache_current_values
|
17
|
+
self.content_type = content_type_from_content || "text/html"
|
18
|
+
|
19
|
+
self.original_filename = filename_from_content_disposition ||
|
20
|
+
filename_from_path ||
|
21
|
+
default_filename
|
22
|
+
@size = @content.size
|
18
23
|
end
|
19
24
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
def content_type_from_content
|
26
|
+
if @content.respond_to?(:content_type)
|
27
|
+
@content.content_type
|
28
|
+
end
|
29
|
+
end
|
24
30
|
|
25
|
-
|
26
|
-
@
|
31
|
+
def filename_from_content_disposition
|
32
|
+
if @content.meta.has_key?("content-disposition")
|
33
|
+
@content.meta["content-disposition"].
|
34
|
+
match(/filename="([^"]*)"/)[1]
|
35
|
+
end
|
36
|
+
end
|
27
37
|
|
28
|
-
|
38
|
+
def filename_from_path
|
39
|
+
@target.path.split("/").last
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_filename
|
43
|
+
"index.html"
|
44
|
+
end
|
45
|
+
|
46
|
+
def download_content
|
47
|
+
open(@target)
|
29
48
|
end
|
30
49
|
|
31
50
|
def copy_to_tempfile(src)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
de:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
in_between: "muss zwischen %{min} und %{max} sein"
|
5
|
+
spoofed_media_type: "trägt eine Dateiendung, die nicht mit dem Inhalt der Datei übereinstimmt"
|
6
|
+
|
7
|
+
number:
|
8
|
+
human:
|
9
|
+
storage_units:
|
10
|
+
format: "%n %u"
|
11
|
+
units:
|
12
|
+
byte:
|
13
|
+
one: "Byte"
|
14
|
+
other: "Bytes"
|
15
|
+
kb: "KB"
|
16
|
+
mb: "MB"
|
17
|
+
gb: "GB"
|
18
|
+
tb: "TB"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
es:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
in_between: "debe estar entre %{min} y %{max}"
|
5
|
+
spoofed_media_type: "tiene una extensión que no coincide con su contenido"
|
6
|
+
|
7
|
+
number:
|
8
|
+
human:
|
9
|
+
storage_units:
|
10
|
+
format: "%n %u"
|
11
|
+
units:
|
12
|
+
byte:
|
13
|
+
one: "Byte"
|
14
|
+
other: "Bytes"
|
15
|
+
kb: "KB"
|
16
|
+
mb: "MB"
|
17
|
+
gb: "GB"
|
18
|
+
tb: "TB"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
ja:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
in_between: "の容量は%{min}以上%{max}以下にしてください。"
|
5
|
+
spoofed_media_type: "の拡張子と内容が一致していません。"
|
6
|
+
|
7
|
+
number:
|
8
|
+
human:
|
9
|
+
storage_units:
|
10
|
+
format: "%n %u"
|
11
|
+
units:
|
12
|
+
byte:
|
13
|
+
one: "Byte"
|
14
|
+
other: "Bytes"
|
15
|
+
kb: "KB"
|
16
|
+
mb: "MB"
|
17
|
+
gb: "GB"
|
18
|
+
tb: "TB"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
pt-BR:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
in_between: "deve ter entre %{min} e %{max}"
|
5
|
+
spoofed_media_type: "tem uma extensão que não corresponde ao seu conteúdo"
|
6
|
+
|
7
|
+
number:
|
8
|
+
human:
|
9
|
+
storage_units:
|
10
|
+
format: "%n %u"
|
11
|
+
units:
|
12
|
+
byte:
|
13
|
+
one: "Byte"
|
14
|
+
other: "Bytes"
|
15
|
+
kb: "KB"
|
16
|
+
mb: "MB"
|
17
|
+
gb: "GB"
|
18
|
+
tb: "TB"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
zh-CN:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
in_between: "文件大小必须介于 %{min} 到 %{max} 之间"
|
5
|
+
spoofed_media_type: "扩展名与内容类型不符"
|
6
|
+
|
7
|
+
number:
|
8
|
+
human:
|
9
|
+
storage_units:
|
10
|
+
format: "%n %u"
|
11
|
+
units:
|
12
|
+
byte:
|
13
|
+
one: "Byte"
|
14
|
+
other: "Bytes"
|
15
|
+
kb: "KB"
|
16
|
+
mb: "MB"
|
17
|
+
gb: "GB"
|
18
|
+
tb: "TB"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
zh-HK:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
in_between: "必須介於%{min}到%{max}之間"
|
5
|
+
spoofed_media_type: "副檔名與內容類型不匹配"
|
6
|
+
|
7
|
+
number:
|
8
|
+
human:
|
9
|
+
storage_units:
|
10
|
+
format: "%n %u"
|
11
|
+
units:
|
12
|
+
byte:
|
13
|
+
one: "Byte"
|
14
|
+
other: "Bytes"
|
15
|
+
kb: "KB"
|
16
|
+
mb: "MB"
|
17
|
+
gb: "GB"
|
18
|
+
tb: "TB"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
zh-TW:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
in_between: "檔案大小必須介於 %{min} 到 %{max} 之間"
|
5
|
+
spoofed_media_type: "副檔名與內容類型不符"
|
6
|
+
|
7
|
+
number:
|
8
|
+
human:
|
9
|
+
storage_units:
|
10
|
+
format: "%n %u"
|
11
|
+
units:
|
12
|
+
byte:
|
13
|
+
one: "Byte"
|
14
|
+
other: "Bytes"
|
15
|
+
kb: "KB"
|
16
|
+
mb: "MB"
|
17
|
+
gb: "GB"
|
18
|
+
tb: "TB"
|
@@ -27,9 +27,10 @@ module Paperclip
|
|
27
27
|
"Should have an attachment named #{@attachment_name}"
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def failure_message_when_negated
|
31
31
|
"Should not have an attachment named #{@attachment_name}"
|
32
32
|
end
|
33
|
+
alias negative_failure_message failure_message_when_negated
|
33
34
|
|
34
35
|
def description
|
35
36
|
"have an attachment named #{@attachment_name}"
|
@@ -26,9 +26,10 @@ module Paperclip
|
|
26
26
|
"Attachment #{@attachment_name} should be required"
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def failure_message_when_negated
|
30
30
|
"Attachment #{@attachment_name} should not be required"
|
31
31
|
end
|
32
|
+
alias negative_failure_message failure_message_when_negated
|
32
33
|
|
33
34
|
def description
|
34
35
|
"require presence of attachment #{@attachment_name}"
|
@@ -45,9 +45,10 @@ module Paperclip
|
|
45
45
|
"Attachment #{@attachment_name} must be between #{@low} and #{@high} bytes"
|
46
46
|
end
|
47
47
|
|
48
|
-
def
|
48
|
+
def failure_message_when_negated
|
49
49
|
"Attachment #{@attachment_name} cannot be between #{@low} and #{@high} bytes"
|
50
50
|
end
|
51
|
+
alias negative_failure_message failure_message_when_negated
|
51
52
|
|
52
53
|
def description
|
53
54
|
"validate the size of attachment #{@attachment_name}"
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class MediaTypeSpoofDetector
|
3
|
+
def self.using(file, name, content_type)
|
4
|
+
new(file, name, content_type)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(file, name, content_type)
|
8
|
+
@file = file
|
9
|
+
@name = name
|
10
|
+
@content_type = content_type || ""
|
11
|
+
end
|
12
|
+
|
13
|
+
def spoofed?
|
14
|
+
if has_name? && has_extension? && media_type_mismatch? && mapping_override_mismatch?
|
15
|
+
Paperclip.log("Content Type Spoof: Filename #{File.basename(@name)} (#{supplied_content_type} from Headers, #{content_types_from_name.map(&:to_s)} from Extension), content type discovered from file command: #{calculated_content_type}. See documentation to allow this combination.")
|
16
|
+
true
|
17
|
+
else
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def has_name?
|
25
|
+
@name.present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_extension?
|
29
|
+
File.extname(@name).present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def media_type_mismatch?
|
33
|
+
supplied_type_mismatch? || calculated_type_mismatch?
|
34
|
+
end
|
35
|
+
|
36
|
+
def supplied_type_mismatch?
|
37
|
+
supplied_media_type.present? && !media_types_from_name.include?(supplied_media_type)
|
38
|
+
end
|
39
|
+
|
40
|
+
def calculated_type_mismatch?
|
41
|
+
!media_types_from_name.include?(calculated_media_type)
|
42
|
+
end
|
43
|
+
|
44
|
+
def mapping_override_mismatch?
|
45
|
+
!Array(mapped_content_type).include?(calculated_content_type)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def supplied_content_type
|
50
|
+
@content_type
|
51
|
+
end
|
52
|
+
|
53
|
+
def supplied_media_type
|
54
|
+
@content_type.split("/").first
|
55
|
+
end
|
56
|
+
|
57
|
+
def content_types_from_name
|
58
|
+
@content_types_from_name ||= MIME::Types.type_for(@name)
|
59
|
+
end
|
60
|
+
|
61
|
+
def media_types_from_name
|
62
|
+
@media_types_from_name ||= content_types_from_name.collect(&:media_type)
|
63
|
+
end
|
64
|
+
|
65
|
+
def calculated_content_type
|
66
|
+
@calculated_content_type ||= type_from_file_command.chomp
|
67
|
+
end
|
68
|
+
|
69
|
+
def calculated_media_type
|
70
|
+
@calculated_media_type ||= calculated_content_type.split("/").first
|
71
|
+
end
|
72
|
+
|
73
|
+
def type_from_file_command
|
74
|
+
begin
|
75
|
+
Paperclip.run("file", "-b --mime :file", :file => @file.path).split(/[:;]\s+/).first
|
76
|
+
rescue Cocaine::CommandLineError
|
77
|
+
""
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def mapped_content_type
|
82
|
+
Paperclip.options[:content_type_mappings][filename_extension]
|
83
|
+
end
|
84
|
+
|
85
|
+
def filename_extension
|
86
|
+
File.extname(@name.to_s.downcase).sub(/^\./, '').to_sym
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/paperclip/processor.rb
CHANGED
@@ -45,41 +45,4 @@ module Paperclip
|
|
45
45
|
Paperclip.run('identify', arguments, local_options)
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
49
|
-
module ProcessorHelpers
|
50
|
-
def processor(name) #:nodoc:
|
51
|
-
@known_processors ||= {}
|
52
|
-
if @known_processors[name.to_s]
|
53
|
-
@known_processors[name.to_s]
|
54
|
-
else
|
55
|
-
name = name.to_s.camelize
|
56
|
-
load_processor(name) unless Paperclip.const_defined?(name)
|
57
|
-
processor = Paperclip.const_get(name)
|
58
|
-
@known_processors[name.to_s] = processor
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def load_processor(name)
|
63
|
-
if defined?(Rails.root) && Rails.root
|
64
|
-
require File.expand_path(Rails.root.join("lib", "paperclip_processors", "#{name.underscore}.rb"))
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def clear_processors!
|
69
|
-
@known_processors.try(:clear)
|
70
|
-
end
|
71
|
-
|
72
|
-
# You can add your own processor via the Paperclip configuration. Normally
|
73
|
-
# Paperclip will load all processors from the
|
74
|
-
# Rails.root/lib/paperclip_processors directory, but here you can add any
|
75
|
-
# existing class using this mechanism.
|
76
|
-
#
|
77
|
-
# Paperclip.configure do |c|
|
78
|
-
# c.register_processor :watermarker, WatermarkingProcessor.new
|
79
|
-
# end
|
80
|
-
def register_processor(name, processor)
|
81
|
-
@known_processors ||= {}
|
82
|
-
@known_processors[name.to_s] = processor
|
83
|
-
end
|
84
|
-
end
|
85
48
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module ProcessorHelpers
|
3
|
+
class NoSuchProcessor < StandardError; end
|
4
|
+
|
5
|
+
def processor(name) #:nodoc:
|
6
|
+
@known_processors ||= {}
|
7
|
+
if @known_processors[name.to_s]
|
8
|
+
@known_processors[name.to_s]
|
9
|
+
else
|
10
|
+
name = name.to_s.camelize
|
11
|
+
load_processor(name) unless Paperclip.const_defined?(name)
|
12
|
+
processor = Paperclip.const_get(name)
|
13
|
+
@known_processors[name.to_s] = processor
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_processor(name)
|
18
|
+
if defined?(Rails.root) && Rails.root
|
19
|
+
filename = "#{name.to_s.underscore}.rb"
|
20
|
+
directories = %w(lib/paperclip lib/paperclip_processors)
|
21
|
+
|
22
|
+
required = directories.map do |directory|
|
23
|
+
pathname = File.expand_path(Rails.root.join(directory, filename))
|
24
|
+
file_exists = File.exist?(pathname)
|
25
|
+
require pathname if file_exists
|
26
|
+
file_exists
|
27
|
+
end
|
28
|
+
|
29
|
+
raise LoadError, "Could not find the '#{name}' processor in any of these paths: #{directories.join(', ')}" unless required.any?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear_processors!
|
34
|
+
@known_processors.try(:clear)
|
35
|
+
end
|
36
|
+
|
37
|
+
# You can add your own processor via the Paperclip configuration. Normally
|
38
|
+
# Paperclip will load all processors from the
|
39
|
+
# Rails.root/lib/paperclip_processors directory, but here you can add any
|
40
|
+
# existing class using this mechanism.
|
41
|
+
#
|
42
|
+
# Paperclip.configure do |c|
|
43
|
+
# c.register_processor :watermarker, WatermarkingProcessor.new
|
44
|
+
# end
|
45
|
+
def register_processor(name, processor)
|
46
|
+
@known_processors ||= {}
|
47
|
+
@known_processors[name.to_s] = processor
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class RailsEnvironment
|
3
|
+
def self.get
|
4
|
+
new.get
|
5
|
+
end
|
6
|
+
|
7
|
+
def get
|
8
|
+
if rails_exists? && rails_environment_exists?
|
9
|
+
Rails.env
|
10
|
+
else
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def rails_exists?
|
18
|
+
Object.const_defined?(:Rails)
|
19
|
+
end
|
20
|
+
|
21
|
+
def rails_environment_exists?
|
22
|
+
Rails.respond_to?(:env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/paperclip/schema.rb
CHANGED
@@ -22,9 +22,12 @@ module Paperclip
|
|
22
22
|
def add_attachment(table_name, *attachment_names)
|
23
23
|
raise ArgumentError, "Please specify attachment name in your add_attachment call in your migration." if attachment_names.empty?
|
24
24
|
|
25
|
+
options = attachment_names.extract_options!
|
26
|
+
|
25
27
|
attachment_names.each do |attachment_name|
|
26
28
|
COLUMNS.each_pair do |column_name, column_type|
|
27
|
-
|
29
|
+
column_options = options.merge(options[column_name.to_sym] || {})
|
30
|
+
add_column(table_name, "#{attachment_name}_#{column_name}", column_type, column_options)
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
@@ -32,8 +35,11 @@ module Paperclip
|
|
32
35
|
def remove_attachment(table_name, *attachment_names)
|
33
36
|
raise ArgumentError, "Please specify attachment name in your remove_attachment call in your migration." if attachment_names.empty?
|
34
37
|
|
38
|
+
options = attachment_names.extract_options!
|
39
|
+
|
35
40
|
attachment_names.each do |attachment_name|
|
36
41
|
COLUMNS.each_pair do |column_name, column_type|
|
42
|
+
column_options = options.merge(options[column_name.to_sym] || {})
|
37
43
|
remove_column(table_name, "#{attachment_name}_#{column_name}")
|
38
44
|
end
|
39
45
|
end
|
@@ -47,9 +53,11 @@ module Paperclip
|
|
47
53
|
|
48
54
|
module TableDefinition
|
49
55
|
def attachment(*attachment_names)
|
56
|
+
options = attachment_names.extract_options!
|
50
57
|
attachment_names.each do |attachment_name|
|
51
58
|
COLUMNS.each_pair do |column_name, column_type|
|
52
|
-
|
59
|
+
column_options = options.merge(options[column_name.to_sym] || {})
|
60
|
+
column("#{attachment_name}_#{column_name}", column_type, column_options)
|
53
61
|
end
|
54
62
|
end
|
55
63
|
end
|
@@ -69,7 +69,7 @@ module Paperclip
|
|
69
69
|
while(true)
|
70
70
|
path = File.dirname(path)
|
71
71
|
FileUtils.rmdir(path)
|
72
|
-
break if File.
|
72
|
+
break if File.exist?(path) # Ruby 1.9.2 does not raise if the removal failed.
|
73
73
|
end
|
74
74
|
rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR, Errno::EACCES
|
75
75
|
# Stop trying to remove parent directories
|
@@ -14,6 +14,7 @@ module Paperclip
|
|
14
14
|
# aws_secret_access_key: '<your aws_secret_access_key>'
|
15
15
|
# provider: 'AWS'
|
16
16
|
# region: 'eu-west-1'
|
17
|
+
# scheme: 'https'
|
17
18
|
# * +fog_directory+: This is the name of the S3 bucket that will
|
18
19
|
# store your files. Remember that the bucket must be unique across
|
19
20
|
# all of Amazon S3. If the bucket does not exist, Paperclip will
|
@@ -32,6 +33,10 @@ module Paperclip
|
|
32
33
|
# that is the alias to the S3 domain of your bucket, e.g.
|
33
34
|
# 'http://images.example.com'. This can also be used in
|
34
35
|
# conjunction with Cloudfront (http://aws.amazon.com/cloudfront)
|
36
|
+
# * +fog_options+: (optional) A hash of options that are passed
|
37
|
+
# to fog when the file is created. For example, you could set
|
38
|
+
# the multipart-chunk size to 100MB with a hash:
|
39
|
+
# { :multipart_chunk_size => 104857600 }
|
35
40
|
|
36
41
|
module Fog
|
37
42
|
def self.extended base
|
@@ -97,12 +102,14 @@ module Paperclip
|
|
97
102
|
log("saving #{path(style)}")
|
98
103
|
retried = false
|
99
104
|
begin
|
100
|
-
|
105
|
+
attributes = fog_file.merge(
|
101
106
|
:body => file,
|
102
107
|
:key => path(style),
|
103
108
|
:public => fog_public(style),
|
104
109
|
:content_type => file.content_type
|
105
|
-
)
|
110
|
+
)
|
111
|
+
attributes.merge!(@options[:fog_options]) if @options[:fog_options]
|
112
|
+
directory.files.create(attributes)
|
106
113
|
rescue Excon::Errors::NotFound
|
107
114
|
raise if retried
|
108
115
|
retried = true
|
@@ -131,7 +138,7 @@ module Paperclip
|
|
131
138
|
"#{dynamic_fog_host_for_style(style)}/#{path(style)}"
|
132
139
|
else
|
133
140
|
if fog_credentials[:provider] == 'AWS'
|
134
|
-
"
|
141
|
+
"#{scheme}://#{host_name_for_directory}/#{path(style)}"
|
135
142
|
else
|
136
143
|
directory.files.new(:key => path(style)).public_url
|
137
144
|
end
|
@@ -140,8 +147,9 @@ module Paperclip
|
|
140
147
|
|
141
148
|
def expiring_url(time = (Time.now + 3600), style_name = default_style)
|
142
149
|
time = convert_time(time)
|
143
|
-
|
144
|
-
|
150
|
+
http_url_method = "get_#{scheme}_url"
|
151
|
+
if path(style_name) && directory.files.respond_to?(http_url_method)
|
152
|
+
expiring_url = directory.files.public_send(http_url_method, path(style_name), time)
|
145
153
|
|
146
154
|
if @options[:fog_host]
|
147
155
|
expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style_name))
|
@@ -155,8 +163,7 @@ module Paperclip
|
|
155
163
|
|
156
164
|
def parse_credentials(creds)
|
157
165
|
creds = find_credentials(creds).stringify_keys
|
158
|
-
|
159
|
-
(creds[env] || creds).symbolize_keys
|
166
|
+
(creds[RailsEnvironment.get] || creds).symbolize_keys
|
160
167
|
end
|
161
168
|
|
162
169
|
def copy_to_local_file(style, local_dest_path)
|
@@ -225,6 +232,10 @@ module Paperclip
|
|
225
232
|
|
226
233
|
@directory ||= connection.directories.new(:key => dir)
|
227
234
|
end
|
235
|
+
|
236
|
+
def scheme
|
237
|
+
@scheme ||= fog_credentials[:scheme] || 'https'
|
238
|
+
end
|
228
239
|
end
|
229
240
|
end
|
230
241
|
end
|