Add expires_at option to ActiveStorage::Blob#signed_id

This commit is contained in:
aki 2023-05-03 06:47:33 +09:00 committed by Rafael Mendonça França
parent 5fcc61076d
commit 1f9fbbe213
No known key found for this signature in database
GPG Key ID: FC23B6D0F1EEE948
6 changed files with 62 additions and 10 deletions

@ -1,3 +1,12 @@
* Add `expires_at` option to `ActiveStorage::Blob#signed_id`.
```ruby
rails_blob_path(user.avatar, disposition: "attachment", expires_at: 30.minutes.from_now)
<%= image_tag rails_blob_path(user.avatar.variant(resize: "100x100"), expires_at: 30.minutes.from_now) %>
```
*Aki*
* Allow attaching File and Pathname when assigning attributes, e.g.
```ruby

@ -158,7 +158,7 @@ def compose(blobs, filename:, content_type: nil, metadata: nil)
end
# Returns a signed ID for this blob that's suitable for reference on the client-side without fear of tampering.
def signed_id(purpose: :blob_id, expires_in: nil)
def signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil)
super
end

@ -32,16 +32,17 @@
direct :rails_storage_proxy do |model, options|
expires_in = options.delete(:expires_in) { ActiveStorage.urls_expire_in }
expires_at = options.delete(:expires_at)
if model.respond_to?(:signed_id)
route_for(
:rails_service_blob_proxy,
model.signed_id(expires_in: expires_in),
model.signed_id(expires_in: expires_in, expires_at: expires_at),
model.filename,
options
)
else
signed_blob_id = model.blob.signed_id(expires_in: expires_in)
signed_blob_id = model.blob.signed_id(expires_in: expires_in, expires_at: expires_at)
variation_key = model.variation.key
filename = model.blob.filename
@ -57,16 +58,17 @@
direct :rails_storage_redirect do |model, options|
expires_in = options.delete(:expires_in) { ActiveStorage.urls_expire_in }
expires_at = options.delete(:expires_at)
if model.respond_to?(:signed_id)
route_for(
:rails_service_blob,
model.signed_id(expires_in: expires_in),
model.signed_id(expires_in: expires_in, expires_at: expires_at),
model.filename,
options
)
else
signed_blob_id = model.blob.signed_id(expires_in: expires_in)
signed_blob_id = model.blob.signed_id(expires_in: expires_in, expires_at: expires_at)
variation_key = model.variation.key
filename = model.blob.filename

@ -32,18 +32,30 @@ class ActiveStorage::Blobs::ProxyControllerTest < ActionDispatch::IntegrationTes
assert_match(/^attachment; /, response.headers["Content-Disposition"])
end
test "signed ID within expiration date" do
test "signed ID within expiration duration" do
get rails_storage_proxy_url(create_file_blob(filename: "racecar.jpg"), expires_in: 1.minute)
assert_response :success
end
test "Expired signed ID" do
test "Expired signed ID within expiration duration" do
url = rails_storage_proxy_url(create_file_blob(filename: "racecar.jpg"), expires_in: 1.minute)
travel 2.minutes
get url
assert_response :not_found
end
test "signed ID within expiration time" do
get rails_storage_proxy_url(create_file_blob(filename: "racecar.jpg"), expires_at: 1.minute.from_now)
assert_response :success
end
test "Expired signed ID within expiration time" do
url = rails_storage_proxy_url(create_file_blob(filename: "racecar.jpg"), expires_at: 1.minute.from_now)
travel 2.minutes
get url
assert_response :not_found
end
test "single Byte Range" do
get rails_storage_proxy_url(create_file_blob(filename: "racecar.jpg")), headers: { "Range" => "bytes=5-9" }
assert_response :partial_content

@ -19,17 +19,29 @@ class ActiveStorage::Blobs::RedirectControllerTest < ActionDispatch::Integration
assert_equal "max-age=300, private", response.headers["Cache-Control"]
end
test "signed ID within expiration date" do
test "signed ID within expiration duration" do
get rails_storage_redirect_url(@blob, expires_in: 1.minute)
assert_redirected_to(/racecar\.jpg/)
end
test "Expired signed ID" do
test "Expired signed ID within expiration duration" do
url = rails_storage_redirect_url(@blob, expires_in: 1.minute)
travel 2.minutes
get url
assert_response :not_found
end
test "signed ID within expiration time" do
get rails_storage_redirect_url(@blob, expires_at: 1.minute.from_now)
assert_redirected_to(/racecar\.jpg/)
end
test "Expired signed ID within expiration time" do
url = rails_storage_redirect_url(@blob, expires_at: 1.minute.from_now)
travel 2.minutes
get url
assert_response :not_found
end
end
class ActiveStorage::Blobs::ExpiringRedirectControllerTest < ActionDispatch::IntegrationTest

@ -108,7 +108,7 @@ class ActiveStorage::AttachmentTest < ActiveSupport::TestCase
assert_equal blob, ActiveStorage::Blob.find_signed!(signed_id)
end
test "fail to find blob within expiration date" do
test "fail to find blob within expiration duration" do
blob = create_blob
@user.avatar.attach(blob)
@ -117,6 +117,23 @@ class ActiveStorage::AttachmentTest < ActiveSupport::TestCase
assert_nil ActiveStorage::Blob.find_signed(signed_id)
end
test "getting a signed blob ID from an attachment with a expires_at" do
blob = create_blob
@user.avatar.attach(blob)
signed_id = @user.avatar.signed_id(expires_at: 1.minute.from_now)
assert_equal blob, ActiveStorage::Blob.find_signed!(signed_id)
end
test "fail to find blob within expiration time" do
blob = create_blob
@user.avatar.attach(blob)
signed_id = @user.avatar.signed_id(expires_at: 1.minute.from_now)
travel 2.minutes
assert_nil ActiveStorage::Blob.find_signed(signed_id)
end
test "signed blob ID backwards compatibility" do
blob = create_blob
@user.avatar.attach(blob)