Allow encryption without compression

Add a `compress` option to ActiveRecord::Encryption::Encryptor, which
defaults to `true`. When set to `false`, the encryptor will never
compress the data.

This is useful for cases where the data is already compressed.

This can be used with the `encryptor` option in the model:

```ruby
class Record < ApplicationRecord
  encrypts :field, encryptor: ActiveRecord::Encryption::Encryptor.new(compress: false)
end
```
This commit is contained in:
Donal McBreen 2024-01-19 14:53:33 +00:00 committed by Rafael Mendonça França
parent 12343bdc53
commit 8c3d4f2b24
No known key found for this signature in database
GPG Key ID: FC23B6D0F1EEE948
3 changed files with 34 additions and 1 deletions

@ -1,3 +1,15 @@
* Add an option to `ActiveRecord::Encryption::Encryptor` to disable compression
Allow compression to be disabled by setting `compress: false`
```ruby
class User
encrypts :name, encryptor: ActiveRecord::Encryption::Encryptor.new(compress: false)
end
```
*Donal McBreen*
* Deprecate passing strings to `ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename`.
A `ActiveRecord::DatabaseConfigurations::DatabaseConfig` object should be passed instead.

@ -12,6 +12,14 @@ module Encryption
# It interacts with a KeyProvider for getting the keys, and delegate to
# ActiveRecord::Encryption::Cipher the actual encryption algorithm.
class Encryptor
# === Options
#
# * <tt>:compress</tt> - Boolean indicating whether records should be compressed before encryption.
# Defaults to +true+.
def initialize(compress: true)
@compress = compress
end
# Encrypts +clean_text+ and returns the encrypted result
#
# Internally, it will:
@ -111,13 +119,17 @@ def serializer
# Under certain threshold, ZIP compression is actually worse that not compressing
def compress_if_worth_it(string)
if string.bytesize > THRESHOLD_TO_JUSTIFY_COMPRESSION
if compress? && string.bytesize > THRESHOLD_TO_JUSTIFY_COMPRESSION
[compress(string), true]
else
[string, false]
end
end
def compress?
@compress
end
def compress(data)
Zlib::Deflate.deflate(data).tap do |compressed_data|
compressed_data.force_encoding(data.encoding)

@ -48,6 +48,15 @@ class ActiveRecord::Encryption::EncryptorTest < ActiveRecord::EncryptionTestCase
assert cipher_text.bytesize < content.bytesize
end
test "content is not compressed, when disabled" do
@encryptor = ActiveRecord::Encryption::Encryptor.new(compress: false)
content = SecureRandom.hex(5.kilobytes)
cipher_text = @encryptor.encrypt(content)
assert_encrypt_text content
assert cipher_text.bytesize > content.bytesize
end
test "trying to encrypt custom classes raises a ForbiddenClass exception" do
assert_raises ActiveRecord::Encryption::Errors::ForbiddenClass do
@encryptor.encrypt(Struct.new(:name).new("Jorge"))