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
|
# frozen_string_literal: true
module ActiveRecord
module Encryption
# ActiveRecord::Encryption uses encryption contexts to configure the different entities used to
# encrypt/decrypt at a given moment in time.
#
# By default, the library uses a default encryption context. This is the Context that gets configured
# initially via +config.active_record.encryption+ options. Library users can define nested encryption contexts
# when running blocks of code.
#
# See Context.
module Contexts
extend ActiveSupport::Concern
included do
mattr_accessor :default_context, default: Context.new
thread_mattr_accessor :custom_contexts
end
class_methods do
# Configures a custom encryption context to use when running the provided block of code.
#
# It supports overriding all the properties defined in +Context+.
#
# Example:
#
# ActiveRecord::Encryption.with_encryption_context(encryptor: ActiveRecord::Encryption::NullEncryptor.new) do
# ...
# end
#
# Encryption contexts can be nested.
def with_encryption_context(properties)
self.custom_contexts ||= []
self.custom_contexts << default_context.dup
properties.each do |key, value|
self.current_custom_context.send("#{key}=", value)
end
yield
ensure
self.custom_contexts.pop
end
# Runs the provided block in an encryption context where encryption is disabled:
#
# * Reading encrypted content will return its ciphertexts.
# * Writing encrypted content will write its clear text.
def without_encryption(&block)
with_encryption_context encryptor: ActiveRecord::Encryption::NullEncryptor.new, &block
end
# Runs the provided block in an encryption context where:
#
# * Reading encrypted content will return its ciphertext.
# * Writing encrypted content will fail.
def protecting_encrypted_data(&block)
with_encryption_context encryptor: ActiveRecord::Encryption::EncryptingOnlyEncryptor.new, frozen_encryption: true, &block
end
# Returns the current context. By default it will return the current context.
def context
self.current_custom_context || self.default_context
end
def current_custom_context
self.custom_contexts&.last
end
def reset_default_context
self.default_context = Context.new
end
end
end
end
end
|