shrine 2.19.4 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +485 -43
- data/LICENSE.txt +1 -1
- data/README.md +81 -977
- data/doc/advantages.md +231 -204
- data/doc/attacher.md +304 -153
- data/doc/carrierwave.md +297 -226
- data/doc/changing_derivatives.md +308 -0
- data/doc/changing_location.md +102 -21
- data/doc/changing_storage.md +110 -0
- data/doc/creating_persistence_plugins.md +132 -0
- data/doc/creating_plugins.md +43 -23
- data/doc/creating_storages.md +19 -5
- data/doc/design.md +147 -97
- data/doc/direct_s3.md +38 -28
- data/doc/external/articles.md +63 -0
- data/doc/external/extensions.md +53 -0
- data/doc/external/misc.md +32 -0
- data/doc/getting_started.md +1115 -0
- data/doc/metadata.md +190 -109
- data/doc/multiple_files.md +62 -34
- data/doc/paperclip.md +384 -262
- data/doc/plugins/activerecord.md +177 -46
- data/doc/plugins/add_metadata.md +139 -38
- data/doc/plugins/atomic_helpers.md +217 -0
- data/doc/plugins/backgrounding.md +156 -98
- data/doc/plugins/cached_attachment_data.md +7 -5
- data/doc/plugins/column.md +121 -0
- data/doc/plugins/data_uri.md +23 -22
- data/doc/plugins/default_storage.md +36 -10
- data/doc/plugins/default_url.md +30 -13
- data/doc/plugins/delete_raw.md +4 -2
- data/doc/plugins/derivation_endpoint.md +162 -101
- data/doc/plugins/derivatives.md +829 -0
- data/doc/plugins/determine_mime_type.md +4 -2
- data/doc/plugins/download_endpoint.md +64 -8
- data/doc/plugins/dynamic_storage.md +5 -3
- data/doc/plugins/entity.md +263 -0
- data/doc/plugins/form_assign.md +55 -0
- data/doc/plugins/included.md +31 -8
- data/doc/plugins/infer_extension.md +21 -10
- data/doc/plugins/instrumentation.md +38 -16
- data/doc/plugins/keep_files.md +14 -17
- data/doc/plugins/metadata_attributes.md +42 -13
- data/doc/plugins/mirroring.md +118 -0
- data/doc/plugins/model.md +210 -0
- data/doc/plugins/module_include.md +4 -2
- data/doc/plugins/multi_cache.md +24 -0
- data/doc/plugins/persistence.md +101 -0
- data/doc/plugins/presign_endpoint.md +9 -4
- data/doc/plugins/pretty_location.md +16 -3
- data/doc/plugins/processing.md +4 -2
- data/doc/plugins/rack_file.md +8 -2
- data/doc/plugins/rack_response.md +6 -2
- data/doc/plugins/recache.md +4 -2
- data/doc/plugins/refresh_metadata.md +49 -9
- data/doc/plugins/remote_url.md +84 -47
- data/doc/plugins/remove_attachment.md +27 -6
- data/doc/plugins/remove_invalid.md +21 -6
- data/doc/plugins/restore_cached_data.md +11 -3
- data/doc/plugins/sequel.md +159 -35
- data/doc/plugins/signature.md +16 -5
- data/doc/plugins/store_dimensions.md +14 -2
- data/doc/plugins/tempfile.md +4 -2
- data/doc/plugins/type_predicates.md +96 -0
- data/doc/plugins/upload_endpoint.md +13 -13
- data/doc/plugins/upload_options.md +6 -4
- data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
- data/doc/plugins/validation.md +97 -0
- data/doc/plugins/validation_helpers.md +16 -13
- data/doc/plugins/versions.md +15 -19
- data/doc/processing.md +438 -221
- data/doc/refile.md +185 -167
- data/doc/release_notes/1.0.0.md +4 -0
- data/doc/release_notes/1.1.0.md +6 -2
- data/doc/release_notes/1.2.0.md +4 -0
- data/doc/release_notes/1.3.0.md +4 -0
- data/doc/release_notes/1.4.0.md +4 -0
- data/doc/release_notes/1.4.1.md +4 -0
- data/doc/release_notes/1.4.2.md +4 -0
- data/doc/release_notes/2.0.0.md +4 -0
- data/doc/release_notes/2.0.1.md +4 -0
- data/doc/release_notes/2.1.0.md +4 -0
- data/doc/release_notes/2.1.1.md +4 -0
- data/doc/release_notes/2.10.0.md +4 -0
- data/doc/release_notes/2.10.1.md +4 -0
- data/doc/release_notes/2.11.0.md +4 -0
- data/doc/release_notes/2.12.0.md +4 -0
- data/doc/release_notes/2.13.0.md +4 -0
- data/doc/release_notes/2.14.0.md +5 -1
- data/doc/release_notes/2.15.0.md +11 -7
- data/doc/release_notes/2.16.0.md +4 -0
- data/doc/release_notes/2.17.0.md +4 -0
- data/doc/release_notes/2.18.0.md +4 -0
- data/doc/release_notes/2.19.0.md +6 -3
- data/doc/release_notes/2.2.0.md +4 -0
- data/doc/release_notes/2.3.0.md +4 -0
- data/doc/release_notes/2.3.1.md +4 -0
- data/doc/release_notes/2.4.0.md +4 -0
- data/doc/release_notes/2.4.1.md +4 -0
- data/doc/release_notes/2.5.0.md +4 -0
- data/doc/release_notes/2.6.0.md +4 -0
- data/doc/release_notes/2.6.1.md +4 -0
- data/doc/release_notes/2.7.0.md +4 -0
- data/doc/release_notes/2.8.0.md +4 -0
- data/doc/release_notes/2.9.0.md +4 -0
- data/doc/release_notes/3.0.0.md +981 -0
- data/doc/release_notes/3.0.1.md +22 -0
- data/doc/release_notes/3.1.0.md +73 -0
- data/doc/release_notes/3.2.0.md +96 -0
- data/doc/release_notes/3.2.1.md +31 -0
- data/doc/release_notes/3.2.2.md +14 -0
- data/doc/release_notes/3.3.0.md +105 -0
- data/doc/release_notes/3.4.0.md +35 -0
- data/doc/retrieving_uploads.md +4 -1
- data/doc/securing_uploads.md +60 -37
- data/doc/storage/file_system.md +20 -3
- data/doc/storage/memory.md +19 -0
- data/doc/storage/s3.md +117 -83
- data/doc/testing.md +124 -144
- data/doc/upgrading_to_3.md +710 -0
- data/doc/validation.md +54 -90
- data/lib/shrine/attacher.rb +287 -171
- data/lib/shrine/attachment.rb +13 -46
- data/lib/shrine/plugins/_persistence.rb +93 -0
- data/lib/shrine/plugins/activerecord.rb +77 -34
- data/lib/shrine/plugins/add_metadata.rb +25 -17
- data/lib/shrine/plugins/atomic_helpers.rb +119 -0
- data/lib/shrine/plugins/backgrounding.rb +77 -113
- data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
- data/lib/shrine/plugins/column.rb +102 -0
- data/lib/shrine/plugins/data_uri.rb +38 -36
- data/lib/shrine/plugins/default_storage.rb +45 -15
- data/lib/shrine/plugins/default_url.rb +12 -24
- data/lib/shrine/plugins/default_url_options.rb +3 -30
- data/lib/shrine/plugins/delete_raw.rb +10 -16
- data/lib/shrine/plugins/derivation_endpoint.rb +89 -134
- data/lib/shrine/plugins/derivatives.rb +637 -0
- data/lib/shrine/plugins/determine_mime_type.rb +9 -21
- data/lib/shrine/plugins/download_endpoint.rb +109 -133
- data/lib/shrine/plugins/dynamic_storage.rb +5 -11
- data/lib/shrine/plugins/entity.rb +152 -0
- data/lib/shrine/plugins/form_assign.rb +108 -0
- data/lib/shrine/plugins/included.rb +6 -6
- data/lib/shrine/plugins/infer_extension.rb +13 -20
- data/lib/shrine/plugins/instrumentation.rb +54 -42
- data/lib/shrine/plugins/keep_files.rb +3 -15
- data/lib/shrine/plugins/metadata_attributes.rb +28 -19
- data/lib/shrine/plugins/mirroring.rb +142 -0
- data/lib/shrine/plugins/model.rb +158 -0
- data/lib/shrine/plugins/module_include.rb +3 -3
- data/lib/shrine/plugins/multi_cache.rb +27 -0
- data/lib/shrine/plugins/presign_endpoint.rb +18 -22
- data/lib/shrine/plugins/pretty_location.rb +15 -9
- data/lib/shrine/plugins/processing.rb +22 -9
- data/lib/shrine/plugins/rack_file.rb +2 -42
- data/lib/shrine/plugins/rack_response.rb +15 -10
- data/lib/shrine/plugins/recache.rb +6 -5
- data/lib/shrine/plugins/refresh_metadata.rb +13 -11
- data/lib/shrine/plugins/remote_url.rb +49 -49
- data/lib/shrine/plugins/remove_attachment.rb +10 -6
- data/lib/shrine/plugins/remove_invalid.rb +19 -8
- data/lib/shrine/plugins/restore_cached_data.rb +13 -7
- data/lib/shrine/plugins/sequel.rb +86 -36
- data/lib/shrine/plugins/signature.rb +10 -16
- data/lib/shrine/plugins/store_dimensions.rb +35 -40
- data/lib/shrine/plugins/tempfile.rb +1 -3
- data/lib/shrine/plugins/type_predicates.rb +113 -0
- data/lib/shrine/plugins/upload_endpoint.rb +25 -23
- data/lib/shrine/plugins/upload_options.rb +14 -15
- data/lib/shrine/plugins/url_options.rb +31 -0
- data/lib/shrine/plugins/validation.rb +80 -0
- data/lib/shrine/plugins/validation_helpers.rb +34 -57
- data/lib/shrine/plugins/versions.rb +107 -87
- data/lib/shrine/plugins.rb +22 -0
- data/lib/shrine/storage/file_system.rb +46 -64
- data/lib/shrine/storage/linter.rb +42 -7
- data/lib/shrine/storage/memory.rb +49 -0
- data/lib/shrine/storage/s3.rb +154 -158
- data/lib/shrine/uploaded_file.rb +28 -30
- data/lib/shrine/version.rb +3 -3
- data/lib/shrine.rb +86 -149
- data/shrine.gemspec +9 -10
- metadata +79 -83
- data/doc/migrating_storage.md +0 -76
- data/doc/plugins/backup.md +0 -31
- data/doc/plugins/copy.md +0 -24
- data/doc/plugins/delete_promoted.md +0 -12
- data/doc/plugins/direct_upload.md +0 -172
- data/doc/plugins/hooks.md +0 -58
- data/doc/plugins/logging.md +0 -42
- data/doc/plugins/migration_helpers.md +0 -60
- data/doc/plugins/moving.md +0 -19
- data/doc/plugins/multi_delete.md +0 -20
- data/doc/plugins/parallelize.md +0 -16
- data/doc/plugins/parsed_json.md +0 -23
- data/doc/regenerating_versions.md +0 -143
- data/lib/shrine/plugins/background_helpers.rb +0 -5
- data/lib/shrine/plugins/backup.rb +0 -90
- data/lib/shrine/plugins/copy.rb +0 -50
- data/lib/shrine/plugins/delete_promoted.rb +0 -20
- data/lib/shrine/plugins/direct_upload.rb +0 -217
- data/lib/shrine/plugins/hooks.rb +0 -90
- data/lib/shrine/plugins/logging.rb +0 -142
- data/lib/shrine/plugins/migration_helpers.rb +0 -70
- data/lib/shrine/plugins/moving.rb +0 -57
- data/lib/shrine/plugins/multi_delete.rb +0 -32
- data/lib/shrine/plugins/parallelize.rb +0 -78
- data/lib/shrine/plugins/parsed_json.rb +0 -29
@@ -0,0 +1,22 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.0.1
|
3
|
+
---
|
4
|
+
|
5
|
+
## Regressions
|
6
|
+
|
7
|
+
* Fixed `metadata_attributes` plugin raising an exception when the attachment
|
8
|
+
is removed (assigned to `nil`).
|
9
|
+
|
10
|
+
## Improvements
|
11
|
+
|
12
|
+
* Simplified `UploadedFile#inspect` output:
|
13
|
+
|
14
|
+
```rb
|
15
|
+
# before
|
16
|
+
uploaded_file.inspect
|
17
|
+
#=> #<Shrine::UploadedFile:0x00007fa4e4140d30 @id="cda84bbdab12b2bd41ea34590060a807", @storage_key=:memory, @metadata={"filename"=>nil, "size"=>0, "mime_type"=>nil}>
|
18
|
+
|
19
|
+
# after
|
20
|
+
uploaded_file.inspect
|
21
|
+
#=> #<Shrine::UploadedFile id="488b887dd792b4c82d3fc445140c5a38" storage=:memory metadata={"filename"=>nil, "size"=>0, "mime_type"=>nil}>
|
22
|
+
```
|
@@ -0,0 +1,73 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.1.0
|
3
|
+
---
|
4
|
+
|
5
|
+
## New features
|
6
|
+
|
7
|
+
* The `Attacher#create_derivatives` method now accepts a `:storage` option for
|
8
|
+
specifying the storage to which derivatives should be uploaded.
|
9
|
+
|
10
|
+
```rb
|
11
|
+
# with attachment module
|
12
|
+
photo.image_derivatives!(storage: :other_store)
|
13
|
+
|
14
|
+
# with attacher
|
15
|
+
attacher.create_derivatives(storage: :other_store)
|
16
|
+
```
|
17
|
+
|
18
|
+
* The `Shrine.calculate_signature` now accepts a `:rewind` boolean option for
|
19
|
+
choosing whether the IO object should be rewinded after reading. This is
|
20
|
+
useful if you want to calculate signature from non-rewindable IO objects,
|
21
|
+
such as `IO.pipe`, `Socket`, non-rewindable `Down::ChunkedIO` etc.
|
22
|
+
|
23
|
+
```rb
|
24
|
+
Shrine.signature(io, rewind: false)
|
25
|
+
```
|
26
|
+
|
27
|
+
## Improvements
|
28
|
+
|
29
|
+
* The derivatives processor can now be registered with `Attacher.derivatives`,
|
30
|
+
which is just an alias for `Attacher.derivatives_processor`.
|
31
|
+
|
32
|
+
```rb
|
33
|
+
class ImageUploader < Shrine
|
34
|
+
Attacher.derivatives_processor do |original|
|
35
|
+
# ...
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# can now be written as
|
40
|
+
|
41
|
+
class ImageUploader < Shrine
|
42
|
+
Attacher.derivatives do |original|
|
43
|
+
# ...
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
* The `Attacher#cached?` and `Attacher#stored?` methods now work correctly if
|
49
|
+
temporary/permanent storage identifiers were specified as strings.
|
50
|
+
|
51
|
+
* The `store_dimensions` plugin now properly propagates exceptions when loading
|
52
|
+
the `ruby-vips` gem in `:vips` analyzer.
|
53
|
+
|
54
|
+
* The `add_metadata` plugin now respects inheritance again when defining
|
55
|
+
metadata methods on the `Shrine::UploadedFile` class. In 2.19.0, the
|
56
|
+
`add_metadata` plugin was changed to define metadata methods on the internal
|
57
|
+
`FileMethods` plugin module, which is shared across all uploaders. This
|
58
|
+
change has now been reverted.
|
59
|
+
|
60
|
+
## Backwards compatibility
|
61
|
+
|
62
|
+
* The `Attacher#cache_key` and `Attacher#store_key` methods now always return
|
63
|
+
symbol keys, even if the storage key that was specified was a string key.
|
64
|
+
|
65
|
+
```rb
|
66
|
+
attacher = Shrine::Attacher.new(cache: "cache", store: "store")
|
67
|
+
attacher.cache_key #=> :cache (previously "cache")
|
68
|
+
attacher.store_key #=> :store (previously "store")
|
69
|
+
```
|
70
|
+
|
71
|
+
* The `add_metadata` plugin now defines metadata methods directly on the
|
72
|
+
`UploadedFile` class, which means that if you happen to have been overriding
|
73
|
+
these metadata methods and calling `super`, this won't work anymore.
|
@@ -0,0 +1,96 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.2.0
|
3
|
+
---
|
4
|
+
|
5
|
+
## New features
|
6
|
+
|
7
|
+
* The `type_predicates` plugin has been added, which adds convenient predicate
|
8
|
+
methods to `Shrine::UploadedFile` based on the MIME type.
|
9
|
+
|
10
|
+
```rb
|
11
|
+
# Gemfile
|
12
|
+
gem "mini_mime" # default dependency of type_predicates
|
13
|
+
```
|
14
|
+
```rb
|
15
|
+
Shrine.plugin :type_predicates
|
16
|
+
```
|
17
|
+
|
18
|
+
The plugin adds four predicate methods based on the general type of the file:
|
19
|
+
|
20
|
+
```rb
|
21
|
+
file.image? # returns true for any "image/*" MIME type
|
22
|
+
file.video? # returns true for any "video/*" MIME type
|
23
|
+
file.audio? # returns true for any "audio/*" MIME type
|
24
|
+
file.text? # returns true for any "text/*" MIME type
|
25
|
+
```
|
26
|
+
|
27
|
+
You can also check for specific MIME type using the extension name:
|
28
|
+
|
29
|
+
```rb
|
30
|
+
file.type?(:jpg) # returns true if MIME type is "image/jpeg"
|
31
|
+
file.type?(:svg) # returns true if MIME type is "image/svg+xml"
|
32
|
+
file.type?(:mov) # returns true if MIME type is "video/quicktime"
|
33
|
+
file.type?(:ppt) # returns true if MIME type is "application/vnd.ms-powerpoint"
|
34
|
+
...
|
35
|
+
```
|
36
|
+
|
37
|
+
For convenience, you can create predicate methods for specific file types:
|
38
|
+
|
39
|
+
```rb
|
40
|
+
Shrine.plugin :type_predicates, methods: %i[jpg svg mov ppt]
|
41
|
+
```
|
42
|
+
```rb
|
43
|
+
file.jpg? # returns true if MIME type is "image/jpeg"
|
44
|
+
file.svg? # returns true if MIME type is "image/svg+xml"
|
45
|
+
file.mov? # returns true if MIME type is "video/quicktime"
|
46
|
+
file.ppt? # returns true if MIME type is "application/vnd.ms-powerpoint"
|
47
|
+
```
|
48
|
+
|
49
|
+
* The `#add_metadata` method has been added to the `add_metadata` plugin for
|
50
|
+
adding new metadata to an existing file/attachment.
|
51
|
+
|
52
|
+
```rb
|
53
|
+
attacher.file.metadata #=> { ... }
|
54
|
+
attacher.add_metadata("foo" => "bar")
|
55
|
+
attacher.file.metadata #=> { ..., "foo" => "bar" }
|
56
|
+
```
|
57
|
+
|
58
|
+
## Other improvements
|
59
|
+
|
60
|
+
* The `remove_invalid` plugin now works correctly with `derivatives` plugin.
|
61
|
+
|
62
|
+
* The `remove_invalid` plugin is now also activated when `Attacher#validate`
|
63
|
+
is called manually.
|
64
|
+
|
65
|
+
* The current attached file data can now be assigned back to the attachment
|
66
|
+
attribute, and this operation will be a no-op.
|
67
|
+
|
68
|
+
```rb
|
69
|
+
photo.image #=> #<Shrine::UploadedFile id="foo" storage=:store metadata={...}>
|
70
|
+
photo.image = { "id" => "foo", "storage" => "store", "metadata" => { ... } } # no-op
|
71
|
+
```
|
72
|
+
|
73
|
+
This allows treating the attachment attribute as a persistent attribute,
|
74
|
+
where the current value can be assigned back on record updates.
|
75
|
+
|
76
|
+
* When promoting derivatives, the `:derivative` parameter value was being
|
77
|
+
passed to the uploader as an array. This has been fixed, and the value is now
|
78
|
+
the same as when uploading derivatives directly to permanent storage.
|
79
|
+
|
80
|
+
* The `derivatives` plugin now includes additional `:io` and `:attacher` values
|
81
|
+
in the instrumentation event payload.
|
82
|
+
|
83
|
+
## Backwards compatibility
|
84
|
+
|
85
|
+
* The `validation` plugin now runs validations on `Attacher#attach` and
|
86
|
+
`Attacher#attach_cached`. If you were using `Attacher#change` directly and
|
87
|
+
expecting the validations to be run automatically, you will need to update
|
88
|
+
your code.
|
89
|
+
|
90
|
+
* If you were updating the cached file metadata via file data assignment, this
|
91
|
+
will no longer work.
|
92
|
+
|
93
|
+
```rb
|
94
|
+
photo.image #=> #<Shrine::UploadedFile id="foo" storage=:cache metadata={...}>
|
95
|
+
photo.image = { "id" => "foo", "storage" => "cache", "metadata" => { ... } } # no-op
|
96
|
+
```
|
@@ -0,0 +1,31 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.2.1
|
3
|
+
---
|
4
|
+
|
5
|
+
## Ruby 2.7 compatibility
|
6
|
+
|
7
|
+
* Shrine doesn't trigger [Ruby 2.7 warnings for separation of positional and
|
8
|
+
keyword arguments][kwargs] anymore.
|
9
|
+
|
10
|
+
* Down 5.1.0 has been released, which resolves warnings and a `FrozenError`
|
11
|
+
exception on Ruby 2.7. Shrine now requires at least this version of Down.
|
12
|
+
|
13
|
+
If you're using `Down::Http`, make sure you're using http.rb 4.3.0 or newer.
|
14
|
+
|
15
|
+
* ImageProcessing 1.10.3 gem has been released which resolves Ruby 2.7 warnings
|
16
|
+
as well. If you're using it for image processing, make sure to upgrade to
|
17
|
+
this version:
|
18
|
+
|
19
|
+
```rb
|
20
|
+
gem "image_processing", ">= 1.10.3", "< 2"
|
21
|
+
```
|
22
|
+
|
23
|
+
## Rack 2.1 compatibility
|
24
|
+
|
25
|
+
* The `derivation_endpoint` plugin now uses `Rack::Files` on Rack 2.1 or newer.
|
26
|
+
|
27
|
+
## Other improvements
|
28
|
+
|
29
|
+
* The `S3#open` method now handles empty S3 objects.
|
30
|
+
|
31
|
+
[kwargs]: https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
|
@@ -0,0 +1,14 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.2.2
|
3
|
+
---
|
4
|
+
|
5
|
+
## Bug fixes
|
6
|
+
|
7
|
+
* aws-sdk-core 3.104.0 introduced a backwards incompatible changes that caused
|
8
|
+
`Shrine::Storage::S3#open` to start raising an exception.
|
9
|
+
|
10
|
+
```
|
11
|
+
NoMethodError: undefined method `bytesize' for #<Array:0x000000000a721be0>
|
12
|
+
```
|
13
|
+
|
14
|
+
This has now been fixed.
|
@@ -0,0 +1,105 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.3.0
|
3
|
+
---
|
4
|
+
|
5
|
+
## New features
|
6
|
+
|
7
|
+
* The `:create_on_promote` option has been added to the `derivatives` plugin
|
8
|
+
for automatically creating derivatives after the attached cached file is
|
9
|
+
promoted to permanent storage.
|
10
|
+
|
11
|
+
```rb
|
12
|
+
Shrine.plugin :derivatives, create_on_promote: true
|
13
|
+
```
|
14
|
+
|
15
|
+
* The `:auto_extraction` option has been added to the `store_dimensions` plugin
|
16
|
+
for skipping automatically extracting dimensions on upload.
|
17
|
+
|
18
|
+
```rb
|
19
|
+
Shrine.plugin :store_dimensions, auto_extraction: false
|
20
|
+
```
|
21
|
+
|
22
|
+
* The `:skip_nil` option has been added to the `add_metadata` plugin for
|
23
|
+
excluding metadata keys whose values are nil.
|
24
|
+
|
25
|
+
```rb
|
26
|
+
class PdfUploader < Shrine
|
27
|
+
add_metadata :pages, skip_nil: true do |io|
|
28
|
+
if is_pdf?(io)
|
29
|
+
reader = PDF::Reader.new(io)
|
30
|
+
reader.page_count
|
31
|
+
else
|
32
|
+
# If this is not a PDF, then the pages metadata will not be stored
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
* The `:download` option has been added to derivatives processors in
|
40
|
+
`derivatives` plugin for skipping converting the source IO object into a
|
41
|
+
file. This can be used to avoid a potentially expensive download/copy when
|
42
|
+
the derivatives processor doesn't need the file.
|
43
|
+
|
44
|
+
```rb
|
45
|
+
Attacher.derivatives :my_processor, download: false do |source|
|
46
|
+
source #=> Could be File, Shrine::UploadedFile, or other IO-like object
|
47
|
+
shrine_class.with_file(source) do |file|
|
48
|
+
# can force download/copy if necessary with `with_file`,
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
## Bug fixes
|
54
|
+
|
55
|
+
* The `upload_endpoint` now handles calling `Shrine.upload_response` method
|
56
|
+
from a Rails controller.
|
57
|
+
|
58
|
+
* The `derivation_endpoint` plugin now applies the `version` query parameter
|
59
|
+
to the derivation when creating the response.
|
60
|
+
|
61
|
+
## Other improvements
|
62
|
+
|
63
|
+
* The new `Aws:S3::EncryptionV2::Client` is now supported by the S3 storage for
|
64
|
+
client-side encryption.
|
65
|
+
|
66
|
+
* The `derivation_endpoint` now reduces the possibility of timing attacks by
|
67
|
+
comparing URL signatures in constant time using `Rack::Utils.secure_compare`.
|
68
|
+
|
69
|
+
* The `derivatives` plugin now copies non-file source IO objects to disk before
|
70
|
+
passing them to the processor. This is consistent with how a
|
71
|
+
`Shrine::UploadedFile` object is downloaded to disk.
|
72
|
+
|
73
|
+
* The `sequel` and `activerecord` plugins now call `Attacher#reload` when
|
74
|
+
reloading the model, which reloads the attached files but keeps other
|
75
|
+
attacher state.
|
76
|
+
|
77
|
+
* The `derivatives` plugin doesn't download the attached file anymore if
|
78
|
+
attempting to process derivatives when no derivatives processor was defined.
|
79
|
+
|
80
|
+
* The `mirroring` plugin now forwards attacher options when uploading to mirror
|
81
|
+
storages.
|
82
|
+
|
83
|
+
* The `presign_endpoint` plugin now handles the `OPTIONS` HTTP verb, which
|
84
|
+
newer versions of Uppy are requesting.
|
85
|
+
|
86
|
+
* `Shrine::Storage::Memory#open` now always returns a `StringIO` in the file
|
87
|
+
content's original encoding, instead of the encoding set by
|
88
|
+
`Encoding.default_internal`. This works around a [bug][ruby-lang #16497]
|
89
|
+
in `StringIO` introduced in Ruby 2.7.0.
|
90
|
+
|
91
|
+
* The `remove_attachment` plugin now deletes the removed file if a new file was
|
92
|
+
attached right after removal.
|
93
|
+
|
94
|
+
## Backwards compatibility
|
95
|
+
|
96
|
+
* If you were passing a non-file IO object to the derivatives processor, Shrine
|
97
|
+
will now convert it into a file beforehand. If you're currently doing this
|
98
|
+
and are converting the IO object into a file inside the processor, you can
|
99
|
+
now remove the conversion code to avoid doubling the amount of disk writes.
|
100
|
+
|
101
|
+
* When reloading a Sequel/ActiveRecord model, any attacher state other than
|
102
|
+
uploaded files will now be retained after the reload. If you were relying on
|
103
|
+
all the attacher state being re-initialized, you'll need to update your code.
|
104
|
+
|
105
|
+
[ruby-lang #16497]: https://bugs.ruby-lang.org/issues/16497
|
@@ -0,0 +1,35 @@
|
|
1
|
+
---
|
2
|
+
title: Shrine 3.4.0
|
3
|
+
---
|
4
|
+
|
5
|
+
* Passing attacher options to `Shrine.Attachment` method now works on Ruby 3.0.
|
6
|
+
|
7
|
+
* Defining validation errors as an array of I18n key and options in
|
8
|
+
`activerecord` plugin now works on Ruby 3.0.
|
9
|
+
|
10
|
+
* The `:fastimage` MIME type analyzer now correctly detects SVGs as
|
11
|
+
`image/svg+html` in the `determine_mime_type` plugin.
|
12
|
+
|
13
|
+
* The `Shrine::Attacher#read` method provided by the `entity` plugin is now
|
14
|
+
public. This is consistent with `Shrine::Attacher#write` from `model` plugin
|
15
|
+
being public as well.
|
16
|
+
|
17
|
+
* The `Shrine::Attacher#reload` method now resets attachment's dirty state.
|
18
|
+
This means that for a model whose `Attacher#changed?` returns `true`, calling
|
19
|
+
`#reload` on the model will make `Attacher#changed?` return `false`. This was
|
20
|
+
the behaviour before Shrine 3.3.0.
|
21
|
+
|
22
|
+
```rb
|
23
|
+
# before
|
24
|
+
model.file_attacher.changed? #=> true
|
25
|
+
model.reload
|
26
|
+
model.file_attacher.changed? #=> true
|
27
|
+
|
28
|
+
# after
|
29
|
+
model.file_attacher.changed? #=> true
|
30
|
+
model.reload
|
31
|
+
model.file_attacher.changed? #=> false
|
32
|
+
```
|
33
|
+
|
34
|
+
* Calling `#reload` on the model will not initialize a `Shrine::Attacher`
|
35
|
+
instance anymore if one hasn't previously been initialized.
|
data/doc/retrieving_uploads.md
CHANGED
data/doc/securing_uploads.md
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
id: securing-uploads
|
3
|
+
title: Securing Uploads
|
4
|
+
---
|
2
5
|
|
3
6
|
Shrine does a lot to make your file uploads secure, but there are still a lot
|
4
7
|
of security measures that could be added by the user on the application's side.
|
5
|
-
This guide will try to cover
|
6
|
-
|
8
|
+
This guide will try to cover some well-known security issues, ranging from the
|
9
|
+
obvious ones to not-so-obvious ones, and try to provide solutions.
|
7
10
|
|
8
11
|
## Validate file type
|
9
12
|
|
@@ -12,17 +15,21 @@ idea to create a whitelist (or a blacklist) of extensions and MIME types.
|
|
12
15
|
|
13
16
|
By default Shrine stores the MIME type derived from the extension, which means
|
14
17
|
it's not guaranteed to hold the actual MIME type of the the file. However, you
|
15
|
-
can load the `determine_mime_type` plugin
|
16
|
-
|
18
|
+
can load the `determine_mime_type` plugin to determine MIME type from magic
|
19
|
+
file headers.
|
17
20
|
|
21
|
+
```rb
|
22
|
+
# Gemfile
|
23
|
+
gem "marcel", "~> 0.3"
|
24
|
+
```
|
18
25
|
```rb
|
19
26
|
class MyUploader < Shrine
|
27
|
+
plugin :determine_mime_type, analyzer: :marcel
|
20
28
|
plugin :validation_helpers
|
21
|
-
plugin :determine_mime_type
|
22
29
|
|
23
30
|
Attacher.validate do
|
24
|
-
|
25
|
-
|
31
|
+
validate_extension %w[jpg jpeg png webp]
|
32
|
+
validate_mime_type %w[image/jpeg image/png image/webp]
|
26
33
|
end
|
27
34
|
end
|
28
35
|
```
|
@@ -31,22 +38,23 @@ end
|
|
31
38
|
|
32
39
|
It's a good idea to generally limit the filesize of uploaded files, so that
|
33
40
|
attackers cannot easily flood your storage. There are various layers at which
|
34
|
-
you can apply filesize limits, depending on how you're accepting uploads.
|
35
|
-
|
36
|
-
|
41
|
+
you can apply filesize limits, depending on how you're accepting uploads. For
|
42
|
+
starters you can add a filesize validation to prevent large files from being
|
43
|
+
uploaded to `:store`:
|
37
44
|
|
38
45
|
```rb
|
39
46
|
class MyUploader < Shrine
|
40
47
|
plugin :validation_helpers
|
41
48
|
|
42
49
|
Attacher.validate do
|
43
|
-
validate_max_size
|
50
|
+
validate_max_size 100*1024*1024 # 100 MB
|
44
51
|
end
|
45
52
|
end
|
46
53
|
```
|
47
54
|
|
48
|
-
In the following sections we talk about various strategies to prevent files
|
49
|
-
being uploaded to
|
55
|
+
In the following sections we talk about various strategies to prevent files
|
56
|
+
from being uploaded to Shrine's temporary storage and the system's temporary
|
57
|
+
directory.
|
50
58
|
|
51
59
|
### Limiting filesize in direct uploads
|
52
60
|
|
@@ -55,7 +63,7 @@ in the `:max_size` option to reject files that are larger than the specified
|
|
55
63
|
limit:
|
56
64
|
|
57
65
|
```rb
|
58
|
-
plugin :upload_endpoint, max_size:
|
66
|
+
plugin :upload_endpoint, max_size: 100*1024*1024 # 100 MB
|
59
67
|
```
|
60
68
|
|
61
69
|
If you're doing direct uploads to Amazon S3 using the `presign_endpoint`
|
@@ -63,7 +71,7 @@ plugin, you can pass in the `:content_length_range` presign option:
|
|
63
71
|
|
64
72
|
```rb
|
65
73
|
plugin :presign_endpoint, presign_options: -> (request) do
|
66
|
-
{ content_length_range: 0..
|
74
|
+
{ content_length_range: 0..100*1024*1024 }
|
67
75
|
end
|
68
76
|
```
|
69
77
|
|
@@ -92,20 +100,17 @@ loading the `remove_invalid` plugin.
|
|
92
100
|
plugin :remove_invalid
|
93
101
|
```
|
94
102
|
|
95
|
-
###
|
103
|
+
### Failsafe filesize limiting
|
96
104
|
|
97
|
-
If you want to make sure that no large files ever get to your storages, and
|
98
|
-
|
99
|
-
and raise an error:
|
105
|
+
If you want to make sure that no large files ever get to your storages, and you
|
106
|
+
don't really care about the error message, you can override `Shrine#upload`:
|
100
107
|
|
101
108
|
```rb
|
102
|
-
class MyUploader
|
103
|
-
|
109
|
+
class MyUploader < Shrine
|
110
|
+
def upload(io, **options)
|
111
|
+
fail FileTooLarge if io.size >= 100*1024*1024
|
104
112
|
|
105
|
-
|
106
|
-
if io.respond_to?(:read)
|
107
|
-
raise FileTooLarge if io.size >= 20*1024*1024
|
108
|
-
end
|
113
|
+
super
|
109
114
|
end
|
110
115
|
end
|
111
116
|
```
|
@@ -118,24 +123,43 @@ image processing, since processing them can take a lot of time and memory. This
|
|
118
123
|
makes it trivial to DoS the application which doesn't have any protection
|
119
124
|
against them.
|
120
125
|
|
121
|
-
|
122
|
-
|
123
|
-
you still need to prevent those files from being attached and processed:
|
126
|
+
So, in addition to validating filesize, we should also validate image
|
127
|
+
dimensions:
|
124
128
|
|
125
129
|
```rb
|
126
|
-
|
130
|
+
# Gemfile
|
131
|
+
gem "fastimage"
|
132
|
+
```
|
133
|
+
```rb
|
134
|
+
class ImageUploader < Shrine
|
127
135
|
plugin :store_dimensions
|
128
136
|
plugin :validation_helpers
|
129
137
|
|
130
138
|
Attacher.validate do
|
131
|
-
|
132
|
-
|
139
|
+
validate_max_size 100*1024*1024
|
140
|
+
|
141
|
+
if validate_mime_type %w[image/jpeg image/png image/webp]
|
142
|
+
validate_max_dimensions [5000, 5000]
|
143
|
+
end
|
133
144
|
end
|
134
145
|
end
|
135
146
|
```
|
136
147
|
|
137
|
-
If you
|
138
|
-
|
148
|
+
If you want to be extra safe, you can add a failsafe before performing
|
149
|
+
processing:
|
150
|
+
|
151
|
+
```rb
|
152
|
+
class ImageUploader < Shrine
|
153
|
+
# ...
|
154
|
+
Attacher.derivatives do |original|
|
155
|
+
width, height = Shrine.dimensions(original)
|
156
|
+
|
157
|
+
fail ImageBombError if width > 5000 || height > 5000
|
158
|
+
|
159
|
+
# ...
|
160
|
+
end
|
161
|
+
end
|
162
|
+
```
|
139
163
|
|
140
164
|
## Prevent metadata tampering
|
141
165
|
|
@@ -153,7 +177,7 @@ app. To guard yourself from such attacks, you can load the
|
|
153
177
|
cached files on assignment and override the received metadata.
|
154
178
|
|
155
179
|
```rb
|
156
|
-
plugin :restore_cached_data
|
180
|
+
Shrine.plugin :restore_cached_data
|
157
181
|
```
|
158
182
|
|
159
183
|
## Limit number of files
|
@@ -172,6 +196,7 @@ class MyUploader < Shrine
|
|
172
196
|
|
173
197
|
Attacher.validate do
|
174
198
|
validate_min_size 10*1024 # 10 KB
|
199
|
+
# ...
|
175
200
|
end
|
176
201
|
end
|
177
202
|
```
|
@@ -183,6 +208,4 @@ end
|
|
183
208
|
* [AppSec: 8 Basic Rules to Implement Secure File Uploads](https://software-security.sans.org/blog/2009/12/28/8-basic-rules-to-implement-secure-file-uploads/)
|
184
209
|
|
185
210
|
[image bombs]: https://www.bamsoftware.com/hacks/deflate.html
|
186
|
-
[fastimage]: https://github.com/sdsykes/fastimage
|
187
|
-
[file]: http://linux.die.net/man/1/file
|
188
211
|
[rack-attack]: https://github.com/kickstarter/rack-attack
|
data/doc/storage/file_system.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
id: file-system
|
3
|
+
title: File System
|
4
|
+
---
|
2
5
|
|
3
6
|
The FileSystem storage handles uploads to the filesystem, and it is most
|
4
7
|
commonly initialized with a "base" folder and a "prefix":
|
@@ -64,7 +67,12 @@ File.exist?(file.path) #=> false
|
|
64
67
|
```
|
65
68
|
|
66
69
|
If you want to make this option default, you can use the
|
67
|
-
[`upload_options`][upload_options] plugin
|
70
|
+
[`upload_options`][upload_options] plugin, provided that both `:cache` and
|
71
|
+
`:store` storages are `FileSystem`):
|
72
|
+
|
73
|
+
```rb
|
74
|
+
plugin :upload_options, cache: { move: true }, store: { move: true }
|
75
|
+
```
|
68
76
|
|
69
77
|
## Path
|
70
78
|
|
@@ -74,6 +82,15 @@ You can retrieve path to the file using `#path`:
|
|
74
82
|
storage.path("image.jpg") #=> #<Pathname:public/image.jpg>
|
75
83
|
```
|
76
84
|
|
85
|
+
## Deleting prefixed
|
86
|
+
|
87
|
+
If you want to delete all files in some directory, you can use
|
88
|
+
`FileSystem#delete_prefixed`:
|
89
|
+
|
90
|
+
```rb
|
91
|
+
storage.delete_prefixed("some_directory/") # deletes all files in "some_directory/"
|
92
|
+
```
|
93
|
+
|
77
94
|
## Clearing cache
|
78
95
|
|
79
96
|
If you're using FileSystem as cache, you will probably want to periodically
|
@@ -111,4 +128,4 @@ also means that deploying the app can cancel someone's uploading if you're
|
|
111
128
|
using backgrounding. Also, by default you cannot generate URLs to files in the
|
112
129
|
"tmp" directory, but you can with the `download_endpoint` plugin.
|
113
130
|
|
114
|
-
[upload_options]: /
|
131
|
+
[upload_options]: https://shrinerb.com/docs/plugins/upload_options
|
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
title: Memory
|
3
|
+
---
|
4
|
+
|
5
|
+
The Memory storage stores uploaded files in memory, which is suitable for
|
6
|
+
testing.
|
7
|
+
|
8
|
+
```rb
|
9
|
+
Shrine.storages[:store] = Shrine::Storage::Memory.new
|
10
|
+
```
|
11
|
+
|
12
|
+
By default, each storage instance uses a new Hash object for storing files,
|
13
|
+
but you can pass your own:
|
14
|
+
|
15
|
+
```rb
|
16
|
+
my_store = Hash.new
|
17
|
+
|
18
|
+
Shrine.storages[:store] = Shrine::Storage::Memory.new(my_store)
|
19
|
+
```
|