class ActiveRecord::Encryption::EncryptedAttributeType

An ActiveModel::Type that encrypts/decrypts strings of text.

This is the central piece that connects the encryption system with encrypts declarations in the model classes. Whenever you declare an attribute as encrypted, it configures an EncryptedAttributeType for that attribute.

Attributes

cast_type[R]
scheme[R]

Public Class Methods

new(scheme:, cast_type: ActiveModel::Type::String.new, previous_type: false) click to toggle source

Options

  • :scheme - A Scheme with the encryption properties for this attribute.

  • :cast_type - A type that will be used to serialize (before encrypting) and deserialize (after decrypting). ActiveModel::Type::String by default.

Calls superclass method
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 23
def initialize(scheme:, cast_type: ActiveModel::Type::String.new, previous_type: false)
  super()
  @scheme = scheme
  @cast_type = cast_type
  @previous_type = previous_type
end

Public Instance Methods

changed_in_place?(raw_old_value, new_value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 42
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
deserialize(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 30
def deserialize(value)
  cast_type.deserialize decrypt(value)
end
serialize(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 34
def serialize(value)
  if serialize_with_oldest?
    serialize_with_oldest(value)
  else
    serialize_with_current(value)
  end
end

Private Instance Methods

build_previous_types_for(schemes) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 61
def build_previous_types_for(schemes)
  schemes.collect do |scheme|
    EncryptedAttributeType.new(scheme: scheme, previous_type: true)
  end
end
clean_text_scheme() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 135
def clean_text_scheme
  @clean_text_scheme ||= ActiveRecord::Encryption::Scheme.new(downcase: downcase?, encryptor: ActiveRecord::Encryption::NullEncryptor.new)
end
decrypt(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 71
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
decryption_options() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 131
def decryption_options
  @decryption_options ||= { key_provider: key_provider }.compact
end
encrypt(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 113
def encrypt(value)
  with_context do
    encryptor.encrypt(value, **encryption_options)
  end
end
encryption_options() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 127
def encryption_options
  @encryption_options ||= { key_provider: key_provider, cipher_options: { deterministic: deterministic? } }.compact
end
encryptor() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 119
def encryptor
  ActiveRecord::Encryption.encryptor
end
handle_deserialize_error(error, value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 91
def handle_deserialize_error(error, value)
  if error.is_a?(Errors::Decryption) && support_unencrypted_data?
    value
  else
    raise error
  end
end
previous_schemes_including_clean_text() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 53
def previous_schemes_including_clean_text
  previous_schemes.including((clean_text_scheme if support_unencrypted_data?)).compact
end
previous_type?() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 67
def previous_type?
  @previous_type
end
previous_types_without_clean_text() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 57
def previous_types_without_clean_text
  @previous_types_without_clean_text ||= build_previous_types_for(previous_schemes)
end
serialize_with_current(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 107
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
serialize_with_oldest(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 103
def serialize_with_oldest(value)
  previous_types.first.serialize(value)
end
serialize_with_oldest?() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 99
def serialize_with_oldest?
  @serialize_with_oldest ||= fixed? && previous_types_without_clean_text.present?
end
support_unencrypted_data?() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 123
def support_unencrypted_data?
  ActiveRecord::Encryption.config.support_unencrypted_data && !previous_type?
end
try_to_deserialize_with_previous_encrypted_types(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 83
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