Skip to content

Commit

Permalink
Encryption: allow turning on support_unencrypted_data at a per-attr…
Browse files Browse the repository at this point in the history
…ibute level

rails#49072 allowed you to turn `support_unencrypted_data` on a global level, then turn it off for specific attributes. But it didn't allow the inverse: you couldn't turn the config off globally, and then turn it on for a specific attribute.

This PR adds support for that.
  • Loading branch information
ghiculescu committed Feb 16, 2024
1 parent 9e01d93 commit d2ddf62
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
23 changes: 23 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
* Encryption now supports `support_unencrypted_data: true` being set per-attribute.

Previously this only worked if `ActiveRecord::Encryption.config.support_unencrypted_data == true`.
Now, if the global config is turned off, you can still opt in for a specific attribute.

```ruby
# ActiveRecord::Encryption.config.support_unencrypted_data = true
class User < ActiveRecord::Base
encrypts :name, support_unencrypted_data: false # only supports encrypted data
encrypts :email # supports encrypted or unencrypted data
end
```

```ruby
# ActiveRecord::Encryption.config.support_unencrypted_data = false
class User < ActiveRecord::Base
encrypts :name, support_unencrypted_data: true # supports encrypted or unencrypted data
encrypts :email # only supports encrypted data
end
```

*Alex Ghiculescu*

* Add support for encrypting binary columns

Ensure encryption and decryption pass `Type::Binary::Data` around for binary data.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ module EncryptableRecord
# will use the oldest encryption scheme to encrypt new data by default. You can change this by setting
# <tt>deterministic: { fixed: false }</tt>. That will make it use the newest encryption scheme for encrypting new
# data.
# * <tt>:support_unencrypted_data</tt> - If `config.active_record.encryption.support_unencrypted_data` is +true+,
# you can set this to +false+ to opt out of unencrypted data support for this attribute. This is useful for
# scenarios where you encrypt one column, and want to disable support for unencrypted data without having to tweak
# the global setting.
# * <tt>:support_unencrypted_data</tt> - When true, unencrypted data can be read normally. When false, it will raise errors.
# Falls back to +config.active_record.encryption.support_unencrypted_data+ if no value is provided.
# This is useful for scenarios where you encrypt one column, and want to disable support for unencrypted data
# without having to tweak the global setting.
# * <tt>:downcase</tt> - When true, it converts the encrypted content to downcase automatically. This allows to
# effectively ignore case when querying data. Notice that the case is lost. Use +:ignore_case+ if you are interested
# in preserving it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def previous_types # :nodoc:
end

def support_unencrypted_data?
ActiveRecord::Encryption.config.support_unencrypted_data && scheme.support_unencrypted_data? && !previous_type?
scheme.support_unencrypted_data? && !previous_type?
end

private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require "cases/encryption/helper"
require "models/book_encrypted"
require "active_support/core_ext/object/with"

class ActiveRecord::Encryption::ExtendedDeterministicQueriesTest < ActiveRecord::EncryptionTestCase
setup do
Expand Down Expand Up @@ -78,4 +79,20 @@ class ActiveRecord::Encryption::ExtendedDeterministicQueriesTest < ActiveRecord:
assert EncryptedBookWithUnencryptedDataOptedIn.find_by(name: "Dune") # core
assert EncryptedBookWithUnencryptedDataOptedIn.where("id > 0").find_by(name: "Dune") # relation
end

test "if support_unencrypted_data config is disabled, but support_unencrypted_data is opted in at an attribute level, can find unencrypted data" do
ActiveRecord::Encryption.config.with(support_unencrypted_data: false) do
UnencryptedBook.create! name: "Dune"
assert EncryptedBookWithUnencryptedDataOptedIn.find_by(name: "Dune") # core
assert EncryptedBookWithUnencryptedDataOptedIn.where("id > 0").find_by(name: "Dune") # relation
end
end

test "if support_unencrypted_data config is disabled, but support_unencrypted_data is opted in at an attribute level, can find encrypted data" do
ActiveRecord::Encryption.config.with(support_unencrypted_data: false) do
EncryptedBook.create! name: "Dune"
assert EncryptedBookWithUnencryptedDataOptedIn.find_by(name: "Dune") # core
assert EncryptedBookWithUnencryptedDataOptedIn.where("id > 0").find_by(name: "Dune") # relation
end
end
end

0 comments on commit d2ddf62

Please sign in to comment.