class ActiveRecord::Encryption::EncryptedAttributeType
for that attribute.
model classes. Whenever you declare an attribute as encrypted, it configures an EncryptedAttributeType
This is the central piece that connects the encryption system with encrypts
declarations in the
An ActiveModel::Type::Value that encrypts/decrypts strings of text.
def build_previous_types_for(schemes)
def build_previous_types_for(schemes) schemes.collect do |scheme| EncryptedAttributeType.new(scheme: scheme, previous_type: true) 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 != new_value end
def clean_text_scheme
def clean_text_scheme @clean_text_scheme ||= ActiveRecord::Encryption::Scheme.new(downcase: downcase?, encryptor: ActiveRecord::Encryption::NullEncryptor.new) end
def decrypt(value)
def decrypt(value) with_context do encryptor.decrypt(value, **decryption_options) unless value.nil? end rescue ActiveRecord::Encryption::Errors::Base => error if previous_types_without_clean_text.blank? handle_deserialize_error(error, value) else try_to_deserialize_with_previous_encrypted_types(value) end end
def decryption_options
def decryption_options @decryption_options ||= { key_provider: key_provider }.compact end
def deserialize(value)
def deserialize(value) cast_type.deserialize decrypt(value) end
def encrypt(value)
def encrypt(value) with_context do encryptor.encrypt(value, **encryption_options) end end
def encryption_options
def encryption_options @encryption_options ||= { key_provider: key_provider, cipher_options: { deterministic: deterministic? } }.compact end
def encryptor
def encryptor ActiveRecord::Encryption.encryptor end
def handle_deserialize_error(error, value)
def handle_deserialize_error(error, value) if error.is_a?(Errors::Decryption) && support_unencrypted_data? value else raise error end end
def initialize(scheme:, cast_type: ActiveModel::Type::String.new, previous_type: false)
* :cast_type - A type that will be used to serialize (before encrypting) and deserialize
* :scheme - A +Scheme+ with the encryption properties for this attribute.
=== Options
def initialize(scheme:, cast_type: ActiveModel::Type::String.new, previous_type: false) super() @scheme = scheme @cast_type = cast_type @previous_type = previous_type end
def previous_schemes_including_clean_text
def previous_schemes_including_clean_text previous_schemes.including((clean_text_scheme if support_unencrypted_data?)).compact end
def previous_type?
def previous_type? @previous_type end
def previous_types # :nodoc:
def previous_types # :nodoc: @previous_types ||= {} # Memoizing on support_unencrypted_data so that we can tweak it during tests @previous_types[support_unencrypted_data?] ||= build_previous_types_for(previous_schemes_including_clean_text) end
def previous_types_without_clean_text
def previous_types_without_clean_text @previous_types_without_clean_text ||= build_previous_types_for(previous_schemes) end
def serialize(value)
def serialize(value) if serialize_with_oldest? serialize_with_oldest(value) else serialize_with_current(value) end end
def serialize_with_current(value)
def serialize_with_current(value) casted_value = cast_type.serialize(value) casted_value = casted_value&.downcase if downcase? encrypt(casted_value.to_s) unless casted_value.nil? end
def serialize_with_oldest(value)
def serialize_with_oldest(value) previous_types.first.serialize(value) end
def serialize_with_oldest?
def serialize_with_oldest? @serialize_with_oldest ||= fixed? && previous_types_without_clean_text.present? end
def support_unencrypted_data?
def support_unencrypted_data? ActiveRecord::Encryption.config.support_unencrypted_data && !previous_type? end
def try_to_deserialize_with_previous_encrypted_types(value)
def try_to_deserialize_with_previous_encrypted_types(value) previous_types.each.with_index do |type, index| break type.deserialize(value) rescue ActiveRecord::Encryption::Errors::Base => error handle_deserialize_error(error, value) if index == previous_types.length - 1 end end