9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
# File 'lib/active_storage_encryption/overrides.rb', line 9
def self.included base
base.class_eval do
encrypts :encryption_key
validates :encryption_key, presence: {message: "must be present for this service"}, if: :service_encrypted?
class << self
ENCRYPTION_KEY_LENGTH_BYTES = 16 + 32
def service_encrypted?(service_name)
return false unless service_name
service = ActiveStorage::Blob.services.fetch(service_name) do
ActiveStorage::Blob.service
end
!!service&.try(:encrypted?)
end
def generate_random_encryption_key
SecureRandom.bytes(ENCRYPTION_KEY_LENGTH_BYTES)
end
def create_before_direct_upload!(filename:, byte_size:, checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil, key: nil, encryption_key: nil)
encryption_key = service_encrypted?(service_name) ? (encryption_key || generate_random_encryption_key) : nil
create!(key: key, filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type, metadata: metadata, service_name: service_name, encryption_key: encryption_key)
end
def create_and_upload!(io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil, key: nil, encryption_key: nil)
create_after_unfurling!(key: key, io: io, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, identify: identify, encryption_key:).tap do |blob|
blob.upload_without_unfurling(io)
end
end
def build_after_unfurling(io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil, key: nil, encryption_key: nil)
new(key: key, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, encryption_key:).tap do |blob|
blob.unfurl(io, identify: identify)
blob.encryption_key ||= service_encrypted?(service_name) ? (encryption_key || generate_random_encryption_key) : nil
end
end
def create_after_unfurling!(io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil, key: nil, encryption_key: nil)
build_after_unfurling(key: key, io: io, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, identify: identify, encryption_key:).tap(&:save!)
end
def compose(blobs, filename:, content_type: nil, metadata: nil, key: nil, service_name: nil, encryption_key: nil)
raise ActiveRecord::RecordNotSaved, "All blobs must be persisted." if blobs.any?(&:new_record?)
content_type ||= blobs.pluck(:content_type).compact.first
new(key: key, filename: filename, content_type: content_type, metadata: metadata, byte_size: blobs.sum(&:byte_size), service_name:, encryption_key:).tap do |combined_blob|
combined_blob.compose(blobs.pluck(:key), source_encryption_keys: blobs.pluck(:encryption_key))
combined_blob.save!
end
end
end
end
end
|