class ActiveRecord::Encryption::EncryptedAttributeType

An ActiveModel::Type::Value 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, default: nil) 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, default: nil)
  super()
  @scheme = scheme
  @cast_type = cast_type
  @previous_type = previous_type
  @default = default
end

Public Instance Methods

cast(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 31
def cast(value)
  cast_type.cast(value)
end
changed_in_place?(raw_old_value, new_value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 51
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 35
def deserialize(value)
  cast_type.deserialize decrypt(value)
end
encrypted?(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 47
def encrypted?(value)
  with_context { encryptor.encrypted? value }
end
serialize(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 39
def serialize(value)
  if serialize_with_oldest?
    serialize_with_oldest(value)
  else
    serialize_with_current(value)
  end
end
support_unencrypted_data?() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 61
def support_unencrypted_data?
  ActiveRecord::Encryption.config.support_unencrypted_data && scheme.support_unencrypted_data? && !previous_type?
end

Private Instance Methods

build_previous_types_for(schemes) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 74
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 162
def clean_text_scheme
  @clean_text_scheme ||= ActiveRecord::Encryption::Scheme.new(downcase: downcase?, encryptor: ActiveRecord::Encryption::NullEncryptor.new)
end
database_type_to_text(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 174
def database_type_to_text(value)
  if value && cast_type.binary?
    binary_cast_type = cast_type.serialized? ? cast_type.subtype : cast_type
    binary_cast_type.deserialize(value)
  else
    value
  end
end
decrypt(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 102
def decrypt(value)
  text_to_database_type decrypt_as_text(database_type_to_text(value))
end
decrypt_as_text(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 84
def decrypt_as_text(value)
  with_context do
    unless value.nil?
      if @default && @default == value
        value
      else
        encryptor.decrypt(value, **decryption_options)
      end
    end
  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 158
def decryption_options
  { key_provider: key_provider }.compact
end
encrypt(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 146
def encrypt(value)
  text_to_database_type encrypt_as_text(value)
end
encrypt_as_text(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 136
def encrypt_as_text(value)
  with_context do
    if encryptor.binary? && !cast_type.binary?
      raise Errors::Encoding, "Binary encoded data can only be stored in binary columns"
    end

    encryptor.encrypt(value, **encryption_options)
  end
end
encryption_options() click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 154
def 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 150
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 114
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 66
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 80
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 70
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 130
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 126
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 122
def serialize_with_oldest?
  @serialize_with_oldest ||= fixed? && previous_types_without_clean_text.present?
end
text_to_database_type(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 166
def text_to_database_type(value)
  if value && cast_type.binary?
    ActiveModel::Type::Binary::Data.new(value)
  else
    value
  end
end
try_to_deserialize_with_previous_encrypted_types(value) click to toggle source
# File lib/active_record/encryption/encrypted_attribute_type.rb, line 106
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