модуль ActiveRecord::Encryption::EncryptableRecord
Данный concern добавляется к моделям Active Record для их шифрования. Он добавляет объявление атрибута encrypts, а также API для шифрования и дешифрования записей.
Константы
- ORIGINAL_ATTRIBUTE_PREFIX
Открытые методы экземпляров
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 132
def add_length_validation_for_encrypted_columns
encrypted_attributes&.each do |attribute_name|
validate_column_size attribute_name
end
end # File activerecord/lib/active_record/encryption/encryptable_record.rb, line 157
def ciphertext_for(attribute_name)
if encrypted_attribute?(attribute_name)
read_attribute_before_type_cast(attribute_name)
else
read_attribute_for_database(attribute_name)
end
end Возвращает шифрованный текст для attribute_name.
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 171 def decrypt decrypt_attributes if has_encrypted_attributes? end
Дешифрует все шифруемые атрибуты и сохраняет изменения.
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 58
def deterministic_encrypted_attributes
@deterministic_encrypted_attributes ||= encrypted_attributes&.find_all do |attribute_name|
type_for_attribute(attribute_name).deterministic?
end
end Возвращает список детерминированных шифруемых атрибутов в классе модели.
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 166 def encrypt encrypt_attributes if has_encrypted_attributes? end
Шифрует все шифруемые атрибуты и сохраняет изменения.
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 84
def encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
encrypted_attributes << name.to_sym
decorate_attributes([name]) do |name, cast_type|
scheme = scheme_for key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, \
downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
ActiveRecord::Encryption::EncryptedAttributeType.new(scheme: scheme, cast_type: cast_type, default: columns_hash[name.to_s]&.default)
end
preserve_original_encrypted(name) if ignore_case
ActiveRecord::Encryption.encrypted_attribute_was_declared(self, name)
end # File activerecord/lib/active_record/encryption/encryptable_record.rb, line 146 def encrypted_attribute?(attribute_name) name = attribute_name.to_s name = self.class.attribute_aliases[name] || name return false unless self.class.encrypted_attributes&.include? name.to_sym type = type_for_attribute(name) type.encrypted? read_attribute_before_type_cast(name) end
Возвращает, является ли заданный атрибут зашифрованным или нет.
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 49
def encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
self.encrypted_attributes ||= Set.new # not using :default because the instance would be shared across classes
names.each do |name|
encrypt_attribute name, key_provider: key_provider, key: key, deterministic: deterministic, support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, previous: previous, **context_properties
end
end Шифрует атрибут name.
Параметры
-
:key_provider- поставщик ключей для предоставления ключей шифрования и дешифрования. По умолчаниюActiveRecord::Encryption.key_provider. -
:key- пароль для вывода ключа. Это сокращение для:key_provider, который служит для вывода ключей. Оба варианта не могут использоваться одновременно. -
:deterministic- По умолчанию шифрование не является детерминированным. Будет использоваться случайный начальный вектор для каждой операции шифрования. Это означает, что шифрование одного и того же содержимого с одним и тем же ключом дважды сгенерирует разные шифрованные тексты. При установке вtrue, он сгенерирует начальный вектор на основе зашифрованного содержимого. Это означает, что одно и то же содержимое сгенерирует одинаковые шифрованные тексты. Это позволяет выполнять запросы к зашифрованному тексту с помощью Active Record. Детерминированное шифрование по умолчанию будет использовать самую старую схему шифрования для шифрования новых данных. Вы можете изменить это, установивdeterministic: { fixed: false }. Это приведет к использованию новейшей схемы шифрования для шифрования новых данных. -
:support_unencrypted_data- Если ‘config.active_record.encryption.support_unencrypted_data` равноtrue, вы можете установить это вfalseдля отключения поддержки нешифрованных данных для этого атрибута. Это полезно в ситуациях, когда вы шифруете один столбец и хотите отключить поддержку нешифрованных данных, не изменяя глобальное значение. -
:downcase- Если true, автоматически преобразует зашифрованное содержимое в нижний регистр. Это позволяет эффективно игнорировать регистр при запросе данных. Обратите внимание, что регистр теряется. Используйте:ignore_case, если вы заинтересованы в его сохранении. -
:ignore_case- Если true, ведет себя как:downcase, но также сохраняет исходный регистр в специально выделенном столбце +original_<name>+. При чтении зашифрованного содержимого предоставляется версия с исходным регистром. Но вы по-прежнему можете выполнять запросы, которые будут игнорировать регистр. Этот параметр может быть использован только когда:deterministicимеет значение true. -
:context_properties- Дополнительные свойства, которые переопределятContextнастройки при шифровании и дешифровании этого атрибута. Например:encryptor:,cipher:,message_serializer:, и т.д. -
:previous- Список предыдущих схем шифрования. При предоставлении они будут использоваться в порядке, когда производится попытка чтения атрибута. Каждый элемент списка может содержать свойства, поддерживаемыеencrypts. Кроме того, при использовании детерминированного шифрования они будут использоваться для генерации дополнительных шифрованных текстов для проверки в запросах.
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 78
def global_previous_schemes_for(scheme)
ActiveRecord::Encryption.config.previous_schemes.filter_map do |previous_scheme|
scheme.merge(previous_scheme) if scheme.compatible_with?(previous_scheme)
end
end # File activerecord/lib/active_record/encryption/encryptable_record.rb, line 109
def override_accessors_to_preserve_original(name, original_attribute_name)
include(Module.new do
define_method name do
if ((value = super()) && encrypted_attribute?(name)) || !ActiveRecord::Encryption.config.support_unencrypted_data
send(original_attribute_name)
else
value
end
end
define_method "#{name}=" do |value|
self.send "#{original_attribute_name}=", value
super(value)
end
end)
end # File activerecord/lib/active_record/encryption/encryptable_record.rb, line 98
def preserve_original_encrypted(name)
original_attribute_name = "#{ORIGINAL_ATTRIBUTE_PREFIX}#{name}".to_sym
if !ActiveRecord::Encryption.config.support_unencrypted_data && !column_names.include?(original_attribute_name.to_s)
raise Errors::Configuration, "To use :ignore_case for '#{name}' you must create an additional column named '#{original_attribute_name}'"
end
encrypts original_attribute_name
override_accessors_to_preserve_original name, original_attribute_name
end # File activerecord/lib/active_record/encryption/encryptable_record.rb, line 70
def scheme_for(key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)
ActiveRecord::Encryption::Scheme.new(key_provider: key_provider, key: key, deterministic: deterministic,
support_unencrypted_data: support_unencrypted_data, downcase: downcase, ignore_case: ignore_case, **context_properties).tap do |scheme|
scheme.previous_schemes = global_previous_schemes_for(scheme) +
Array.wrap(previous).collect { |scheme_config| ActiveRecord::Encryption::Scheme.new(**scheme_config) }
end
end # File activerecord/lib/active_record/encryption/encryptable_record.rb, line 65 def source_attribute_from_preserved_attribute(attribute_name) attribute_name.to_s.sub(ORIGINAL_ATTRIBUTE_PREFIX, "") if attribute_name.start_with?(ORIGINAL_ATTRIBUTE_PREFIX) end
Принимая имя атрибута, возвращает имя исходного атрибута, если это сохраненный атрибут.
# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 138
def validate_column_size(attribute_name)
if limit = columns_hash[attribute_name.to_s]&.limit
validates_length_of attribute_name, maximum: limit
end
end
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.