跳至內容 跳至搜尋

這是混入 Active Record 模型的 Concern,使其可加密。它增加了 `encrypts` 屬性宣告,以及加密和解密記錄的 API。

方法
A
C
D
E
G
O
P
S
V

常數

ORIGINAL_ATTRIBUTE_PREFIX = "original_"
 

實例公開方法

add_length_validation_for_encrypted_columns()

# 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

ciphertext_for(attribute_name)

返回 `attribute_name` 的密文。

# 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

decrypt()

解密所有可加密的屬性並儲存變更。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 171
def decrypt
  decrypt_attributes if has_encrypted_attributes?
end

deterministic_encrypted_attributes()

返回模型類別中確定性可加密屬性的列表。

# 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

encrypt()

加密所有可加密的屬性並儲存變更。

# File activerecord/lib/active_record/encryption/encryptable_record.rb, line 166
def encrypt
  encrypt_attributes if has_encrypted_attributes?
end

encrypt_attribute(name, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)

# 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: [], compress: true, compressor: nil, **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, compress: compress, compressor: compressor, **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

encrypted_attribute?(attribute_name)

返回給定屬性是否已加密。

# 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

encrypts(*names, key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], compress: true, compressor: nil, **context_properties)

加密 `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_` 中保留原始大小寫。讀取加密的內容時,將提供具有原始大小寫的版本。但您仍然可以執行忽略大小寫的查詢。此選項只能在 `:deterministic` 為 true 時使用。

  • `:context_properties` - 加密和解密此屬性時,將覆蓋 `Context` 設定的其他屬性。例如:`encryptor:`、`cipher:`、`message_serializer:` 等。

  • `:previous` - 先前加密方案的列表。提供時,嘗試讀取屬性時將按順序使用它們。列表的每個條目都可以包含 `encrypts` 支援的屬性。此外,當使用確定性加密時,它們將用於產生額外的密文以在查詢中檢查。

# 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: [], compress: true, compressor: nil, **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, compress: compress, compressor: compressor, **context_properties
  end
end

global_previous_schemes_for(scheme)

# 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

override_accessors_to_preserve_original(name, original_attribute_name)

# 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

preserve_original_encrypted(name)

# 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

scheme_for(key_provider: nil, key: nil, deterministic: false, support_unencrypted_data: nil, downcase: false, ignore_case: false, previous: [], **context_properties)

# 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

source_attribute_from_preserved_attribute(attribute_name)

給定一個屬性名稱,當它是保留屬性時,它會返回來源屬性的名稱。

# 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

validate_column_size(attribute_name)

# 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