1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
# frozen_string_literal: true
module ActiveRecord
module Encryption
# A container of attribute encryption options.
#
# It validates and serves attribute encryption options.
#
# See EncryptedAttributeType, Context
class Scheme
attr_accessor :previous_schemes
def initialize(key_provider: nil, key: nil, deterministic: nil, support_unencrypted_data: nil, downcase: nil, ignore_case: nil,
previous_schemes: nil, **context_properties)
# Initializing all attributes to +nil+ as we want to allow a "not set" semantics so that we
# can merge schemes without overriding values with defaults. See +#merge+
@key_provider_param = key_provider
@key = key
@deterministic = deterministic
@support_unencrypted_data = support_unencrypted_data
@downcase = downcase || ignore_case
@ignore_case = ignore_case
@previous_schemes_param = previous_schemes
@previous_schemes = Array.wrap(previous_schemes)
@context_properties = context_properties
validate_config!
end
def ignore_case?
@ignore_case
end
def downcase?
@downcase
end
def deterministic?
!!@deterministic
end
def support_unencrypted_data?
@support_unencrypted_data.nil? ? ActiveRecord::Encryption.config.support_unencrypted_data : @support_unencrypted_data
end
def fixed?
# by default deterministic encryption is fixed
@fixed ||= @deterministic && (!@deterministic.is_a?(Hash) || @deterministic[:fixed])
end
def key_provider
@key_provider_param || key_provider_from_key || deterministic_key_provider || default_key_provider
end
def merge(other_scheme)
self.class.new(**to_h.merge(other_scheme.to_h))
end
def to_h
{ key_provider: @key_provider_param, deterministic: @deterministic, downcase: @downcase, ignore_case: @ignore_case,
previous_schemes: @previous_schemes_param, **@context_properties }.compact
end
def with_context(&block)
if @context_properties.present?
ActiveRecord::Encryption.with_encryption_context(**@context_properties, &block)
else
block.call
end
end
def compatible_with?(other_scheme)
deterministic? == other_scheme.deterministic?
end
private
def validate_config!
raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
end
def key_provider_from_key
@key_provider_from_key ||= if @key.present?
DerivedSecretKeyProvider.new(@key)
end
end
def deterministic_key_provider
@deterministic_key_provider ||= if @deterministic
DeterministicKeyProvider.new(ActiveRecord::Encryption.config.deterministic_key)
end
end
def default_key_provider
ActiveRecord::Encryption.key_provider
end
end
end
end
|