Download disk blobs with verified URLs

上级 dde68d4a
# FIXME: To be used by DiskSite#url
class ActiveFile::DiskController < ActionController::Base
def show
if verified_key.expired?
head :gone
else
blob = ActiveFile::Blob.find_by!(key: verified_key.to_s)
if key = decode_verified_key
blob = ActiveFile::Blob.find_by!(key: key)
send_data blob.download, filename: blob.filename, type: blob.content_type, disposition: disposition_param
else
head :not_found
end
end
private
def verified_key
ActiveFile::Sites::DiskSite::VerifiedKeyWithExpiration.new(params[:id])
def decode_verified_key
ActiveFile::Sites::DiskSite::VerifiedKeyWithExpiration.decode(params[:id])
end
def disposition_param
......
......@@ -2,42 +2,6 @@
require "pathname"
class ActiveFile::Sites::DiskSite < ActiveFile::Site
class_attribute :verifier, default: -> { Rails.application.message_verifier('ActiveFile::DiskSite') }
class << self
def generate_verifiable_key(key, expires_in:)
VerifiedKeyWithExpiration
end
end
class VerifiableKeyWithExpiration
def initialize(verifiable_key_with_expiration)
verified_key_with_expiration = ActiveFile::Sites::DiskSite.verify(verifiable_key_with_expiration)
@key = verified_key_with_expiration[:key]
@expires_at = verified_key_with_expiration[:expires_at]
end
def expired?
@expires_at && Time.now.utc > @expires_at
end
def decoded
key
end
end
class VerifiedKeyWithExpiration
def initialize(key, expires_in: nil)
@key = key
@expires_at = Time.now.utc.advance(sec: expires_in)
end
def encoded
ActiveFile::Sites::DiskSite.verify.generate({ key: @key, expires_at: @expires_at })
end
end
attr_reader :root
def initialize(root:)
......@@ -75,10 +39,12 @@ def exists?(key)
def url(key, disposition:, expires_in: nil)
verified_key_with_expiration = ActiveFile::VerifiedKeyWithExpiration.encode(key, expires_in: expires_in)
if defined?(Rails)
Rails.application.routes.url_helpers.rails_disk_blob_path(key)
Rails.application.routes.url_helpers.rails_disk_blob_path(verified_key_with_expiration)
else
"/rails/blobs/#{key}"
"/rails/blobs/#{verified_key_with_expiration}"
end
end
......
class ActiveFile::VerifiedKeyWithExpiration
class_attribute :verifier, default: defined?(Rails) ? Rails.application.message_verifier('ActiveFile') : nil
def self.encode(key, expires_in: nil)
verifier.generate([ key, expires_in ? Time.now.utc.advance(sec: expires_in) : nil ])
end
def self.decode(encoded_key)
key, expires_at = verifier.verified(encoded_key)
if key
key if expires_at.nil? || Time.now.utc < expires_at
end
end
end
......@@ -2,8 +2,6 @@
require "database/setup"
require "active_file/blob"
ActiveFile::Blob.site = ActiveFile::Sites::DiskSite.new(root: File.join(Dir.tmpdir, "active_file"))
class ActiveFile::BlobTest < ActiveSupport::TestCase
test "create after upload sets byte size and checksum" do
data = "Hello world!"
......@@ -14,9 +12,12 @@ class ActiveFile::BlobTest < ActiveSupport::TestCase
assert_equal Digest::MD5.hexdigest(data), blob.checksum
end
test "url" do
test "url expiring in 5 minutes" do
blob = create_blob
assert_equal "/rails/blobs/#{blob.key}", blob.url
travel_to Time.now do
assert_equal "/rails/blobs/#{ActiveFile::VerifiedKeyWithExpiration.encode(blob.key, expires_in: 5.minutes)}", blob.url
end
end
private
......
......@@ -4,3 +4,9 @@
require "byebug"
require "active_file"
require "active_file/site"
ActiveFile::Blob.site = ActiveFile::Sites::DiskSite.new(root: File.join(Dir.tmpdir, "active_file"))
require "active_file/verified_key_with_expiration"
ActiveFile::VerifiedKeyWithExpiration.verifier = ActiveSupport::MessageVerifier.new("Testing")
require "test_helper"
require "active_support/core_ext/securerandom"
class ActiveFile::VerifiedKeyWithExpirationTest < ActiveSupport::TestCase
FIXTURE_KEY = SecureRandom.base58(24)
test "without expiration" do
encoded_key = ActiveFile::VerifiedKeyWithExpiration.encode(FIXTURE_KEY)
assert_equal FIXTURE_KEY, ActiveFile::VerifiedKeyWithExpiration.decode(encoded_key)
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册