aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2017-07-06 16:01:11 +0200
committerDavid Heinemeier Hansson <david@loudthinking.com>2017-07-06 16:01:11 +0200
commit894e1e3183b78d62d873454312882df53a29f850 (patch)
tree0a01a8bad85dbe6ba1f536473ce96b5c3e90fbd1
parentef07687262716984db51c173a0378d1eb0664289 (diff)
downloadrails-894e1e3183b78d62d873454312882df53a29f850.tar.gz
rails-894e1e3183b78d62d873454312882df53a29f850.tar.bz2
rails-894e1e3183b78d62d873454312882df53a29f850.zip
Check integrity after uploads
-rw-r--r--lib/active_storage/blob.rb2
-rw-r--r--lib/active_storage/service.rb4
-rw-r--r--lib/active_storage/service/disk_service.rb10
-rw-r--r--lib/active_storage/service/gcs_service.rb3
-rw-r--r--lib/active_storage/service/mirror_service.rb4
-rw-r--r--lib/active_storage/service/s3_service.rb3
-rw-r--r--test/service/shared_service_tests.rb17
7 files changed, 34 insertions, 9 deletions
diff --git a/lib/active_storage/blob.rb b/lib/active_storage/blob.rb
index b10dc2c771..26c116712b 100644
--- a/lib/active_storage/blob.rb
+++ b/lib/active_storage/blob.rb
@@ -45,7 +45,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
self.checksum = compute_checksum_in_chunks(io)
self.byte_size = io.size
- service.upload(key, io)
+ service.upload(key, io, checksum: checksum)
end
def download
diff --git a/lib/active_storage/service.rb b/lib/active_storage/service.rb
index 0d0ebf6010..9aab654d80 100644
--- a/lib/active_storage/service.rb
+++ b/lib/active_storage/service.rb
@@ -1,5 +1,7 @@
# Abstract class serving as an interface for concrete services.
class ActiveStorage::Service
+ class ActiveStorage::IntegrityError < StandardError; end
+
def self.configure(service, **options)
begin
require "active_storage/service/#{service.to_s.downcase}_service"
@@ -10,7 +12,7 @@ class ActiveStorage::Service
end
- def upload(key, io)
+ def upload(key, io, checksum: nil)
raise NotImplementedError
end
diff --git a/lib/active_storage/service/disk_service.rb b/lib/active_storage/service/disk_service.rb
index 668a837663..6164caf86c 100644
--- a/lib/active_storage/service/disk_service.rb
+++ b/lib/active_storage/service/disk_service.rb
@@ -9,12 +9,14 @@ class ActiveStorage::Service::DiskService < ActiveStorage::Service
@root = root
end
- def upload(key, io)
+ def upload(key, io, checksum: nil)
File.open(make_path_for(key), "wb") do |file|
while chunk = io.read(64.kilobytes)
file.write(chunk)
end
end
+
+ ensure_integrity_of(key, checksum) if checksum
end
def download(key)
@@ -59,4 +61,10 @@ class ActiveStorage::Service::DiskService < ActiveStorage::Service
def make_path_for(key)
path_for(key).tap { |path| FileUtils.mkdir_p File.dirname(path) }
end
+
+ def ensure_integrity_of(key, checksum)
+ unless Digest::MD5.file(path_for(key)).base64digest == checksum
+ raise ActiveStorage::IntegrityError
+ end
+ end
end
diff --git a/lib/active_storage/service/gcs_service.rb b/lib/active_storage/service/gcs_service.rb
index c725afb35c..a558791d89 100644
--- a/lib/active_storage/service/gcs_service.rb
+++ b/lib/active_storage/service/gcs_service.rb
@@ -9,7 +9,8 @@ class ActiveStorage::Service::GCSService < ActiveStorage::Service
@bucket = @client.bucket(bucket)
end
- def upload(key, io)
+ def upload(key, io, checksum: nil)
+ # FIXME: Ensure integrity by sending the checksum for service side verification
bucket.create_file(io, key)
end
diff --git a/lib/active_storage/service/mirror_service.rb b/lib/active_storage/service/mirror_service.rb
index 0d37ad96a3..59ad3fc472 100644
--- a/lib/active_storage/service/mirror_service.rb
+++ b/lib/active_storage/service/mirror_service.rb
@@ -9,9 +9,9 @@ class ActiveStorage::Service::MirrorService < ActiveStorage::Service
@services = services
end
- def upload(key, io)
+ def upload(key, io, checksum: nil)
services.collect do |service|
- service.upload key, io
+ service.upload key, io, checksum: checksum
io.rewind
end
end
diff --git a/lib/active_storage/service/s3_service.rb b/lib/active_storage/service/s3_service.rb
index 746a636912..fd8ef6e9a6 100644
--- a/lib/active_storage/service/s3_service.rb
+++ b/lib/active_storage/service/s3_service.rb
@@ -9,7 +9,8 @@ class ActiveStorage::Service::S3Service < ActiveStorage::Service
@bucket = @client.bucket(bucket)
end
- def upload(key, io)
+ def upload(key, io, checksum: nil)
+ # FIXME: Ensure integrity by sending the checksum for service side verification
object_for(key).put(body: io)
end
diff --git a/test/service/shared_service_tests.rb b/test/service/shared_service_tests.rb
index 3676272e27..b4c888e77c 100644
--- a/test/service/shared_service_tests.rb
+++ b/test/service/shared_service_tests.rb
@@ -26,11 +26,11 @@ module ActiveStorage::Service::SharedServiceTests
FIXTURE_FILE.rewind
end
- test "uploading" do
+ test "uploading with integrity" do
begin
key = SecureRandom.base58(24)
data = "Something else entirely!"
- @service.upload(key, StringIO.new(data))
+ @service.upload(key, StringIO.new(data), checksum: Digest::MD5.base64digest(data))
assert_equal data, @service.download(key)
ensure
@@ -38,6 +38,19 @@ module ActiveStorage::Service::SharedServiceTests
end
end
+ test "upload without integrity" do
+ begin
+ key = SecureRandom.base58(24)
+ data = "Something else entirely!"
+
+ assert_raises(ActiveStorage::IntegrityError) do
+ @service.upload(key, StringIO.new(data), checksum: "BAD_CHECKSUM")
+ end
+ ensure
+ @service.delete key
+ end
+ end
+
test "downloading" do
assert_equal FIXTURE_FILE.read, @service.download(FIXTURE_KEY)
end