mirror of https://github.com/rails/rails
Support encrypted attributes on columns with default values
Before, it was failing to read these columns because their contents were not encrypted, unless you enabled `config.active_record.encryption.support_unencrypted_data`. Now, it will detect the change at creation time for these records and effectively encrypt those values, preventing the problem. Fixes #44314 #43664 Closes #44993 Co-authored-by: Dima Fatko <fatkodima123@gmail.com>
This commit is contained in:
parent
480edd4906
commit
238432d1cb
|
@ -1,3 +1,11 @@
|
||||||
|
* Support encrypted attributes on columns with default db values.
|
||||||
|
|
||||||
|
This adds support for encrypted attributes defined on columns with default values.
|
||||||
|
It will encrypt those values at creation time. Before, it would raise an
|
||||||
|
error unless `config.active_record.encryption.support_unencrypted_data` was true.
|
||||||
|
|
||||||
|
*Jorge Manrubia* and *Dima Fatko*
|
||||||
|
|
||||||
* Allow overriding `reading_request?` in `DatabaseSelector::Resolver`
|
* Allow overriding `reading_request?` in `DatabaseSelector::Resolver`
|
||||||
|
|
||||||
The default implementation checks if a request is a `get?` or `head?`,
|
The default implementation checks if a request is a `get?` or `head?`,
|
||||||
|
|
|
@ -82,7 +82,7 @@ module ActiveRecord
|
||||||
def encrypt_attribute(name, attribute_scheme)
|
def encrypt_attribute(name, attribute_scheme)
|
||||||
encrypted_attributes << name.to_sym
|
encrypted_attributes << name.to_sym
|
||||||
|
|
||||||
attribute name do |cast_type|
|
attribute name, default: -> { columns_hash[name.to_s]&.default } do |cast_type|
|
||||||
ActiveRecord::Encryption::EncryptedAttributeType.new scheme: attribute_scheme, cast_type: cast_type
|
ActiveRecord::Encryption::EncryptedAttributeType.new scheme: attribute_scheme, cast_type: cast_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def changed_in_place?(raw_old_value, new_value)
|
def changed_in_place?(raw_old_value, new_value)
|
||||||
old_value = raw_old_value.nil? ? nil : deserialize(raw_old_value)
|
old_value = raw_old_value.nil? ? nil : deserialize_previous_value_to_determine_change(raw_old_value)
|
||||||
old_value != new_value
|
old_value != new_value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -135,6 +135,14 @@ module ActiveRecord
|
||||||
def clean_text_scheme
|
def clean_text_scheme
|
||||||
@clean_text_scheme ||= ActiveRecord::Encryption::Scheme.new(downcase: downcase?, encryptor: ActiveRecord::Encryption::NullEncryptor.new)
|
@clean_text_scheme ||= ActiveRecord::Encryption::Scheme.new(downcase: downcase?, encryptor: ActiveRecord::Encryption::NullEncryptor.new)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def deserialize_previous_value_to_determine_change(raw_old_value)
|
||||||
|
deserialize(raw_old_value)
|
||||||
|
# We tolerate unencrypted data when determining if a column changed
|
||||||
|
# to support default DB values in encrypted attributes
|
||||||
|
rescue ActiveRecord::Encryption::Errors::Decryption
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -292,6 +292,11 @@ class ActiveRecord::Encryption::EncryptableRecordTest < ActiveRecord::Encryption
|
||||||
assert_equal Encoding::US_ASCII, book.reload.name.encoding
|
assert_equal Encoding::US_ASCII, book.reload.name.encoding
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "support encrypted attributes defined on columns with default values" do
|
||||||
|
book = EncryptedBook.create!
|
||||||
|
assert_encrypted_attribute(book, :name, "<untitled>")
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
class FailingKeyProvider
|
class FailingKeyProvider
|
||||||
def decryption_key(message) end
|
def decryption_key(message) end
|
||||||
|
|
|
@ -141,7 +141,7 @@ ActiveRecord::Schema.define do
|
||||||
create_table :encrypted_books, id: :integer, force: true do |t|
|
create_table :encrypted_books, id: :integer, force: true do |t|
|
||||||
t.references :author
|
t.references :author
|
||||||
t.string :format
|
t.string :format
|
||||||
t.column :name, :string
|
t.column :name, :string, default: "<untitled>"
|
||||||
t.column :original_name, :string
|
t.column :original_name, :string
|
||||||
|
|
||||||
t.datetime :created_at
|
t.datetime :created_at
|
||||||
|
|
Loading…
Reference in New Issue