shrine 2.19.4 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +485 -43
  3. data/LICENSE.txt +1 -1
  4. data/README.md +81 -977
  5. data/doc/advantages.md +231 -204
  6. data/doc/attacher.md +304 -153
  7. data/doc/carrierwave.md +297 -226
  8. data/doc/changing_derivatives.md +308 -0
  9. data/doc/changing_location.md +102 -21
  10. data/doc/changing_storage.md +110 -0
  11. data/doc/creating_persistence_plugins.md +132 -0
  12. data/doc/creating_plugins.md +43 -23
  13. data/doc/creating_storages.md +19 -5
  14. data/doc/design.md +147 -97
  15. data/doc/direct_s3.md +38 -28
  16. data/doc/external/articles.md +63 -0
  17. data/doc/external/extensions.md +53 -0
  18. data/doc/external/misc.md +32 -0
  19. data/doc/getting_started.md +1115 -0
  20. data/doc/metadata.md +190 -109
  21. data/doc/multiple_files.md +62 -34
  22. data/doc/paperclip.md +384 -262
  23. data/doc/plugins/activerecord.md +177 -46
  24. data/doc/plugins/add_metadata.md +139 -38
  25. data/doc/plugins/atomic_helpers.md +217 -0
  26. data/doc/plugins/backgrounding.md +156 -98
  27. data/doc/plugins/cached_attachment_data.md +7 -5
  28. data/doc/plugins/column.md +121 -0
  29. data/doc/plugins/data_uri.md +23 -22
  30. data/doc/plugins/default_storage.md +36 -10
  31. data/doc/plugins/default_url.md +30 -13
  32. data/doc/plugins/delete_raw.md +4 -2
  33. data/doc/plugins/derivation_endpoint.md +162 -101
  34. data/doc/plugins/derivatives.md +829 -0
  35. data/doc/plugins/determine_mime_type.md +4 -2
  36. data/doc/plugins/download_endpoint.md +64 -8
  37. data/doc/plugins/dynamic_storage.md +5 -3
  38. data/doc/plugins/entity.md +263 -0
  39. data/doc/plugins/form_assign.md +55 -0
  40. data/doc/plugins/included.md +31 -8
  41. data/doc/plugins/infer_extension.md +21 -10
  42. data/doc/plugins/instrumentation.md +38 -16
  43. data/doc/plugins/keep_files.md +14 -17
  44. data/doc/plugins/metadata_attributes.md +42 -13
  45. data/doc/plugins/mirroring.md +118 -0
  46. data/doc/plugins/model.md +210 -0
  47. data/doc/plugins/module_include.md +4 -2
  48. data/doc/plugins/multi_cache.md +24 -0
  49. data/doc/plugins/persistence.md +101 -0
  50. data/doc/plugins/presign_endpoint.md +9 -4
  51. data/doc/plugins/pretty_location.md +16 -3
  52. data/doc/plugins/processing.md +4 -2
  53. data/doc/plugins/rack_file.md +8 -2
  54. data/doc/plugins/rack_response.md +6 -2
  55. data/doc/plugins/recache.md +4 -2
  56. data/doc/plugins/refresh_metadata.md +49 -9
  57. data/doc/plugins/remote_url.md +84 -47
  58. data/doc/plugins/remove_attachment.md +27 -6
  59. data/doc/plugins/remove_invalid.md +21 -6
  60. data/doc/plugins/restore_cached_data.md +11 -3
  61. data/doc/plugins/sequel.md +159 -35
  62. data/doc/plugins/signature.md +16 -5
  63. data/doc/plugins/store_dimensions.md +14 -2
  64. data/doc/plugins/tempfile.md +4 -2
  65. data/doc/plugins/type_predicates.md +96 -0
  66. data/doc/plugins/upload_endpoint.md +13 -13
  67. data/doc/plugins/upload_options.md +6 -4
  68. data/doc/plugins/{default_url_options.md → url_options.md} +9 -7
  69. data/doc/plugins/validation.md +97 -0
  70. data/doc/plugins/validation_helpers.md +16 -13
  71. data/doc/plugins/versions.md +15 -19
  72. data/doc/processing.md +438 -221
  73. data/doc/refile.md +185 -167
  74. data/doc/release_notes/1.0.0.md +4 -0
  75. data/doc/release_notes/1.1.0.md +6 -2
  76. data/doc/release_notes/1.2.0.md +4 -0
  77. data/doc/release_notes/1.3.0.md +4 -0
  78. data/doc/release_notes/1.4.0.md +4 -0
  79. data/doc/release_notes/1.4.1.md +4 -0
  80. data/doc/release_notes/1.4.2.md +4 -0
  81. data/doc/release_notes/2.0.0.md +4 -0
  82. data/doc/release_notes/2.0.1.md +4 -0
  83. data/doc/release_notes/2.1.0.md +4 -0
  84. data/doc/release_notes/2.1.1.md +4 -0
  85. data/doc/release_notes/2.10.0.md +4 -0
  86. data/doc/release_notes/2.10.1.md +4 -0
  87. data/doc/release_notes/2.11.0.md +4 -0
  88. data/doc/release_notes/2.12.0.md +4 -0
  89. data/doc/release_notes/2.13.0.md +4 -0
  90. data/doc/release_notes/2.14.0.md +5 -1
  91. data/doc/release_notes/2.15.0.md +11 -7
  92. data/doc/release_notes/2.16.0.md +4 -0
  93. data/doc/release_notes/2.17.0.md +4 -0
  94. data/doc/release_notes/2.18.0.md +4 -0
  95. data/doc/release_notes/2.19.0.md +6 -3
  96. data/doc/release_notes/2.2.0.md +4 -0
  97. data/doc/release_notes/2.3.0.md +4 -0
  98. data/doc/release_notes/2.3.1.md +4 -0
  99. data/doc/release_notes/2.4.0.md +4 -0
  100. data/doc/release_notes/2.4.1.md +4 -0
  101. data/doc/release_notes/2.5.0.md +4 -0
  102. data/doc/release_notes/2.6.0.md +4 -0
  103. data/doc/release_notes/2.6.1.md +4 -0
  104. data/doc/release_notes/2.7.0.md +4 -0
  105. data/doc/release_notes/2.8.0.md +4 -0
  106. data/doc/release_notes/2.9.0.md +4 -0
  107. data/doc/release_notes/3.0.0.md +981 -0
  108. data/doc/release_notes/3.0.1.md +22 -0
  109. data/doc/release_notes/3.1.0.md +73 -0
  110. data/doc/release_notes/3.2.0.md +96 -0
  111. data/doc/release_notes/3.2.1.md +31 -0
  112. data/doc/release_notes/3.2.2.md +14 -0
  113. data/doc/release_notes/3.3.0.md +105 -0
  114. data/doc/release_notes/3.4.0.md +35 -0
  115. data/doc/retrieving_uploads.md +4 -1
  116. data/doc/securing_uploads.md +60 -37
  117. data/doc/storage/file_system.md +20 -3
  118. data/doc/storage/memory.md +19 -0
  119. data/doc/storage/s3.md +117 -83
  120. data/doc/testing.md +124 -144
  121. data/doc/upgrading_to_3.md +710 -0
  122. data/doc/validation.md +54 -90
  123. data/lib/shrine/attacher.rb +287 -171
  124. data/lib/shrine/attachment.rb +13 -46
  125. data/lib/shrine/plugins/_persistence.rb +93 -0
  126. data/lib/shrine/plugins/activerecord.rb +77 -34
  127. data/lib/shrine/plugins/add_metadata.rb +25 -17
  128. data/lib/shrine/plugins/atomic_helpers.rb +119 -0
  129. data/lib/shrine/plugins/backgrounding.rb +77 -113
  130. data/lib/shrine/plugins/cached_attachment_data.rb +6 -15
  131. data/lib/shrine/plugins/column.rb +102 -0
  132. data/lib/shrine/plugins/data_uri.rb +38 -36
  133. data/lib/shrine/plugins/default_storage.rb +45 -15
  134. data/lib/shrine/plugins/default_url.rb +12 -24
  135. data/lib/shrine/plugins/default_url_options.rb +3 -30
  136. data/lib/shrine/plugins/delete_raw.rb +10 -16
  137. data/lib/shrine/plugins/derivation_endpoint.rb +89 -134
  138. data/lib/shrine/plugins/derivatives.rb +637 -0
  139. data/lib/shrine/plugins/determine_mime_type.rb +9 -21
  140. data/lib/shrine/plugins/download_endpoint.rb +109 -133
  141. data/lib/shrine/plugins/dynamic_storage.rb +5 -11
  142. data/lib/shrine/plugins/entity.rb +152 -0
  143. data/lib/shrine/plugins/form_assign.rb +108 -0
  144. data/lib/shrine/plugins/included.rb +6 -6
  145. data/lib/shrine/plugins/infer_extension.rb +13 -20
  146. data/lib/shrine/plugins/instrumentation.rb +54 -42
  147. data/lib/shrine/plugins/keep_files.rb +3 -15
  148. data/lib/shrine/plugins/metadata_attributes.rb +28 -19
  149. data/lib/shrine/plugins/mirroring.rb +142 -0
  150. data/lib/shrine/plugins/model.rb +158 -0
  151. data/lib/shrine/plugins/module_include.rb +3 -3
  152. data/lib/shrine/plugins/multi_cache.rb +27 -0
  153. data/lib/shrine/plugins/presign_endpoint.rb +18 -22
  154. data/lib/shrine/plugins/pretty_location.rb +15 -9
  155. data/lib/shrine/plugins/processing.rb +22 -9
  156. data/lib/shrine/plugins/rack_file.rb +2 -42
  157. data/lib/shrine/plugins/rack_response.rb +15 -10
  158. data/lib/shrine/plugins/recache.rb +6 -5
  159. data/lib/shrine/plugins/refresh_metadata.rb +13 -11
  160. data/lib/shrine/plugins/remote_url.rb +49 -49
  161. data/lib/shrine/plugins/remove_attachment.rb +10 -6
  162. data/lib/shrine/plugins/remove_invalid.rb +19 -8
  163. data/lib/shrine/plugins/restore_cached_data.rb +13 -7
  164. data/lib/shrine/plugins/sequel.rb +86 -36
  165. data/lib/shrine/plugins/signature.rb +10 -16
  166. data/lib/shrine/plugins/store_dimensions.rb +35 -40
  167. data/lib/shrine/plugins/tempfile.rb +1 -3
  168. data/lib/shrine/plugins/type_predicates.rb +113 -0
  169. data/lib/shrine/plugins/upload_endpoint.rb +25 -23
  170. data/lib/shrine/plugins/upload_options.rb +14 -15
  171. data/lib/shrine/plugins/url_options.rb +31 -0
  172. data/lib/shrine/plugins/validation.rb +80 -0
  173. data/lib/shrine/plugins/validation_helpers.rb +34 -57
  174. data/lib/shrine/plugins/versions.rb +107 -87
  175. data/lib/shrine/plugins.rb +22 -0
  176. data/lib/shrine/storage/file_system.rb +46 -64
  177. data/lib/shrine/storage/linter.rb +42 -7
  178. data/lib/shrine/storage/memory.rb +49 -0
  179. data/lib/shrine/storage/s3.rb +154 -158
  180. data/lib/shrine/uploaded_file.rb +28 -30
  181. data/lib/shrine/version.rb +3 -3
  182. data/lib/shrine.rb +86 -149
  183. data/shrine.gemspec +9 -10
  184. metadata +79 -83
  185. data/doc/migrating_storage.md +0 -76
  186. data/doc/plugins/backup.md +0 -31
  187. data/doc/plugins/copy.md +0 -24
  188. data/doc/plugins/delete_promoted.md +0 -12
  189. data/doc/plugins/direct_upload.md +0 -172
  190. data/doc/plugins/hooks.md +0 -58
  191. data/doc/plugins/logging.md +0 -42
  192. data/doc/plugins/migration_helpers.md +0 -60
  193. data/doc/plugins/moving.md +0 -19
  194. data/doc/plugins/multi_delete.md +0 -20
  195. data/doc/plugins/parallelize.md +0 -16
  196. data/doc/plugins/parsed_json.md +0 -23
  197. data/doc/regenerating_versions.md +0 -143
  198. data/lib/shrine/plugins/background_helpers.rb +0 -5
  199. data/lib/shrine/plugins/backup.rb +0 -90
  200. data/lib/shrine/plugins/copy.rb +0 -50
  201. data/lib/shrine/plugins/delete_promoted.rb +0 -20
  202. data/lib/shrine/plugins/direct_upload.rb +0 -217
  203. data/lib/shrine/plugins/hooks.rb +0 -90
  204. data/lib/shrine/plugins/logging.rb +0 -142
  205. data/lib/shrine/plugins/migration_helpers.rb +0 -70
  206. data/lib/shrine/plugins/moving.rb +0 -57
  207. data/lib/shrine/plugins/multi_delete.rb +0 -32
  208. data/lib/shrine/plugins/parallelize.rb +0 -78
  209. 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.
@@ -1,4 +1,7 @@
1
- # Retrieving Uploads
1
+ ---
2
+ id: retrieving-uploads
3
+ title: Retrieving Uploads
4
+ ---
2
5
 
3
6
  Uploaded file content is typically retrieved from the storage using a
4
7
  `Shrine::UploadedFile` object. This guide explains the various methods of
@@ -1,9 +1,12 @@
1
- # Securing uploads
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 all the well-known security issues, ranging from
6
- the obvious ones to not-so-obvious ones, and try to provide solutions.
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 which by default uses the [file]
16
- utility to determine the MIME type from magic file headers.
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
- validate_extension_inclusion %w[jpg jpeg png gif]
25
- validate_mime_type_inclusion %w[image/jpeg image/png image/gif]
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
- Firstly, you should probably add a filesize validation to prevent large files
36
- from being uploaded to `:store`:
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 20*1024*1024 # 20 MB
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 from
49
- being uploaded to cache and the temporary directory.
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: 20*1024*1024 # 20 MB
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..20*1024*1024 }
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
- ### Paranoid filesize limiting
103
+ ### Failsafe filesize limiting
96
104
 
97
- If you want to make sure that no large files ever get to your storages, and
98
- you don't really care about the error message, you can use the `hooks` plugin
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
- plugin :hooks
109
+ class MyUploader < Shrine
110
+ def upload(io, **options)
111
+ fail FileTooLarge if io.size >= 100*1024*1024
104
112
 
105
- def before_upload(io, context)
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
- Shrine uses the [fastimage] gem for determining image dimensions which has
122
- built-in protection against image bombs (ImageMagick for example doesn't), but
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
- class MyUploader < Shrine
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
- validate_max_width 2500
132
- validate_max_height 2500
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're doing processing on caching, you can use the fastimage gem directly
138
- in a conditional.
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
@@ -1,4 +1,7 @@
1
- # Shrine::Storage::FileSystem
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]: /doc/plugins/upload_options.md#readme
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
+ ```