shrine 3.7.1 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29a02d25cd1180c4f0170434edd185b3b1ab0bd2be060fa53e58fcd32c50d4ae
4
- data.tar.gz: 56e50d961ef88e0d3cae4d295b6996c52cd2021b923d9b453f401f10b04021b3
3
+ metadata.gz: 55c3fc9bf7eb40700d2be0ee82900986c601b1b3449d5d5ee7b246546bfe5eb3
4
+ data.tar.gz: 11ffe3b196b79946c931f5a0e9538bda74cc4abd74711124509c76a13a5eaddc
5
5
  SHA512:
6
- metadata.gz: cb06f261af63f09ba767556d65f8b99e5204c1162ce7d8e28e5355148539a02c486fa088819884cf38dee4bf0683e8167b6582c4a028271a5145bd8661f64765
7
- data.tar.gz: ec5cd4f04fe90ada87cd594bf78e61c2de9fcbebe8d51cb9e49b0bec566614be5ea5826382a8f25608888c84a951f25ad80442a6af2d641a37bae0e8fe184d7e
6
+ metadata.gz: 19585a7a2c486d43fb9be2abc84123adced4d18beebf50919938a9c631d16c0c2ecb15e777397b5b8a1642911171d328c55bf86769b9a31a4a3957cf3d8256d9
7
+ data.tar.gz: 1dfbb667941b5f2bfa1b035230f0b1fb809c59855fc253f8365394624cffd4e3078a0aa41188eb27c8e57be8d4243e45d5dcf56a83b4d9ea1900bf02fa340dc6
data/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
+ ## 3.8.0 (2026-06-24)
2
+
3
+ * `s3` – Use single-request uploads for smaller files again instead of always using multipart uploads (@janko)
4
+
5
+ * `derivatives` – Forward `Attacher#promote` options to `Attacher#upload_derivatives` (@milkcocoa)
6
+
7
+ * `file_system` – Prevent path traversal outside of the storage directory (@janko)
8
+
1
9
  ## 3.7.1 (2026-06-03)
2
10
 
3
- * Update method signatures of some plugins to work around a Bootsnap bug causing a `wrong number of arguments` error.
11
+ * Update method signatures of some plugins to work around a Bootsnap bug causing a `wrong number of arguments` error (@janko)
12
+
13
+ * `derivation_endpoint` – Add `:format` argument to `UploadedFile#derivation_url` for path extension (@janko)
14
+
15
+ * `rack_response` – Add `:etag` argument for setting a custom `ETag` (@camilohollanda)
4
16
 
5
17
  ## 3.7.0 (2026-05-27)
6
18
 
@@ -2,6 +2,24 @@
2
2
  title: Shrine 3.7.1
3
3
  ---
4
4
 
5
+ ## New features
6
+
7
+ * The `derivation_endpoint` plugin now supports adding a file extension to the derivation URL path via the `:format` option on `UploadedFile#derivation_url`. Some HTTP clients and CDNs use the URL path extension to determine the content type of the response.
8
+
9
+ ```rb
10
+ uploaded_file.derivation_url(:thumbnail, format: "jpg")
11
+ #=> ".../thumbnail/eyJpZCI6ImZvbyIsInN.jpg?signature=..."
12
+ ```
13
+
14
+ The extension is included in the URL signature, so it cannot be tampered with.
15
+
16
+ * The `rack_response` plugin now accepts an `:etag` option for setting a custom `ETag` header, overriding the default one Shrine generates.
17
+
18
+ ```rb
19
+ response = uploaded_file.to_rack_response(etag: "my-custom-etag")
20
+ response[1]["ETag"] #=> "my-custom-etag"
21
+ ```
22
+
5
23
  ## Bug fixes
6
24
 
7
25
  * When initializing Shrine with the `activerecord` plugin, under Bootsnap 1.24.5 and Ruby 3.4.5 this would raise an error:
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: Shrine 3.8.0
3
+ ---
4
+
5
+ ## Security
6
+
7
+ * The `file_system` storage now prevents path traversal outside of the storage
8
+ directory. Previously, an id containing `../` sequences (e.g. coming from
9
+ attacker-controlled data) could resolve to a location outside of the
10
+ configured storage directory. Now `Shrine::Error` is raised whenever an id
11
+ would resolve outside of the storage directory:
12
+
13
+ ```rb
14
+ storage = Shrine::Storage::FileSystem.new("uploads")
15
+ storage.open("../../etc/passwd") #~> Shrine::Error
16
+ ```
17
+
18
+ ## New features
19
+
20
+ * The `derivatives` plugin now forwards options passed to `Attacher#promote`
21
+ into `Attacher#upload_derivatives`. This means options such as upload options
22
+ reach the derivatives upload as well, not just the main file.
23
+
24
+ ```rb
25
+ attacher.promote(upload_options: { acl: "public-read" })
26
+ # the same options are now forwarded when uploading derivatives
27
+ ```
28
+
29
+ ## Other improvements
30
+
31
+ * The `s3` storage again uses single-request uploads for smaller files, instead
32
+ of always using multipart uploads. In Shrine 3.7.0, when a `TransferManager`
33
+ was available, it was used for uploads of any size, but `TransferManager`
34
+ uploads via multipart unconditionally, which is inefficient for smaller files.
35
+ Now files at or below the multipart threshold (`:upload`, 15MB by default) are
36
+ uploaded in a single request, and only larger files use multipart upload via
37
+ the `TransferManager` (falling back to the older API when it's not available).
@@ -161,7 +161,7 @@ class Shrine
161
161
  # attacher.stored?(attacher.derivatives[:thumb]) #=> true
162
162
  def promote(**options)
163
163
  super
164
- promote_derivatives
164
+ promote_derivatives(**options)
165
165
  create_derivatives if create_derivatives_on_promote?
166
166
  end
167
167
 
@@ -113,9 +113,18 @@ class Shrine
113
113
  end
114
114
  end
115
115
 
116
- # Returns the full path to the file.
116
+ # Returns the full path to the file. Raises Shrine::Error if the id would
117
+ # resolve to a location outside of the storage #directory (e.g. an id
118
+ # containing `../` path traversal sequences in attacker-controlled data).
117
119
  def path(id)
118
- directory.join(id.gsub("/", File::SEPARATOR))
120
+ path = directory.join(id.gsub("/", File::SEPARATOR))
121
+ expanded = path.expand_path
122
+
123
+ unless expanded == directory || expanded.to_s.start_with?("#{directory}#{File::SEPARATOR}")
124
+ raise Shrine::Error, "path #{id.inspect} resolves outside of the storage directory"
125
+ end
126
+
127
+ path
119
128
  end
120
129
 
121
130
  protected
@@ -230,20 +230,15 @@ class Shrine
230
230
 
231
231
  private
232
232
 
233
- # Upload the file to S3.
234
- # Uses @transfer_manager, if defined, for any size upload.
235
- # Falls back to the original code using the older, now depricated
236
- # AWS APIs for users of older version of the AWS Gem.
237
- # for multipart uploads of large files.
233
+ # Uploads the file to S3. Uses multipart upload for large files.
238
234
  def put(io, id, **)
239
- if @transfer_manager
235
+ if io.respond_to?(:size) && io.size && io.size <= @multipart_threshold[:upload]
236
+ object(id).put(body: io, **)
237
+ elsif @transfer_manager # multipart upload - transfer manager
240
238
  @transfer_manager.upload_stream(bucket: bucket.name, key: object_key(id), part_size: part_size(io), **) do |write_stream|
241
239
  IO.copy_stream(io, write_stream)
242
240
  end
243
- elsif io.respond_to?(:size) && io.size && io.size <= @multipart_threshold[:upload]
244
- object(id).put(body: io, **)
245
- else
246
- # multipart upload old API
241
+ else # multipart upload - before transfer manager
247
242
  object(id).upload_stream(part_size: part_size(io), **) do |write_stream|
248
243
  IO.copy_stream(io, write_stream)
249
244
  end
@@ -7,8 +7,8 @@ class Shrine
7
7
 
8
8
  module VERSION
9
9
  MAJOR = 3
10
- MINOR = 7
11
- TINY = 1
10
+ MINOR = 8
11
+ TINY = 0
12
12
  PRE = nil
13
13
 
14
14
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
data/shrine.gemspec CHANGED
@@ -67,10 +67,10 @@ direct uploads for fully asynchronous user experience.
67
67
 
68
68
  # for instrumentation plugin
69
69
  gem.add_development_dependency "dry-monitor"
70
- gem.add_development_dependency "activesupport", RUBY_ENGINE == "jruby" ? "~> 7.2" : "~> 8.1"
70
+ gem.add_development_dependency "activesupport", RUBY_ENGINE == "jruby" ? "~> 8.0.0" : "~> 8.1"
71
71
 
72
72
  # for ORM plugins
73
73
  gem.add_development_dependency "sequel"
74
- gem.add_development_dependency "activerecord", RUBY_ENGINE == "jruby" ? "~> 7.2" : "~> 8.1"
74
+ gem.add_development_dependency "activerecord", RUBY_ENGINE == "jruby" ? "~> 8.0.0" : "~> 8.1"
75
75
  gem.add_development_dependency "sqlite3", "~> 2.1" unless RUBY_ENGINE == "jruby"
76
76
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shrine
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.1
4
+ version: 3.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
@@ -155,20 +155,6 @@ dependencies:
155
155
  - - ">="
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
- - !ruby/object:Gem::Dependency
159
- name: ruby-filemagic
160
- requirement: !ruby/object:Gem::Requirement
161
- requirements:
162
- - - "~>"
163
- - !ruby/object:Gem::Version
164
- version: '0.7'
165
- type: :development
166
- prerelease: false
167
- version_requirements: !ruby/object:Gem::Requirement
168
- requirements:
169
- - - "~>"
170
- - !ruby/object:Gem::Version
171
- version: '0.7'
172
158
  - !ruby/object:Gem::Dependency
173
159
  name: mime-types
174
160
  requirement: !ruby/object:Gem::Requirement
@@ -301,14 +287,14 @@ dependencies:
301
287
  requirements:
302
288
  - - "~>"
303
289
  - !ruby/object:Gem::Version
304
- version: '8.1'
290
+ version: 8.0.0
305
291
  type: :development
306
292
  prerelease: false
307
293
  version_requirements: !ruby/object:Gem::Requirement
308
294
  requirements:
309
295
  - - "~>"
310
296
  - !ruby/object:Gem::Version
311
- version: '8.1'
297
+ version: 8.0.0
312
298
  - !ruby/object:Gem::Dependency
313
299
  name: sequel
314
300
  requirement: !ruby/object:Gem::Requirement
@@ -329,28 +315,14 @@ dependencies:
329
315
  requirements:
330
316
  - - "~>"
331
317
  - !ruby/object:Gem::Version
332
- version: '8.1'
333
- type: :development
334
- prerelease: false
335
- version_requirements: !ruby/object:Gem::Requirement
336
- requirements:
337
- - - "~>"
338
- - !ruby/object:Gem::Version
339
- version: '8.1'
340
- - !ruby/object:Gem::Dependency
341
- name: sqlite3
342
- requirement: !ruby/object:Gem::Requirement
343
- requirements:
344
- - - "~>"
345
- - !ruby/object:Gem::Version
346
- version: '2.1'
318
+ version: 8.0.0
347
319
  type: :development
348
320
  prerelease: false
349
321
  version_requirements: !ruby/object:Gem::Requirement
350
322
  requirements:
351
323
  - - "~>"
352
324
  - !ruby/object:Gem::Version
353
- version: '2.1'
325
+ version: 8.0.0
354
326
  description: |
355
327
  Shrine is a toolkit for file attachments in Ruby applications. It supports
356
328
  uploading, downloading, processing and deleting IO objects, backed by various
@@ -483,6 +455,7 @@ files:
483
455
  - doc/release_notes/3.6.0.md
484
456
  - doc/release_notes/3.7.0.md
485
457
  - doc/release_notes/3.7.1.md
458
+ - doc/release_notes/3.8.0.md
486
459
  - doc/retrieving_uploads.md
487
460
  - doc/securing_uploads.md
488
461
  - doc/storage/file_system.md
@@ -576,7 +549,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
576
549
  - !ruby/object:Gem::Version
577
550
  version: '0'
578
551
  requirements: []
579
- rubygems_version: 3.6.9
552
+ rubygems_version: 4.0.3
580
553
  specification_version: 4
581
554
  summary: Toolkit for file attachments in Ruby applications
582
555
  test_files: []