module Vault::EncryptedModel::ClassMethods
Public Instance Methods
__vault_attributes()
click to toggle source
The list of Vault
attributes.
@return [Hash]
# File lib/vault/encrypted_model.rb, line 101 def __vault_attributes @vault_attributes ||= {} end
_vault_validate_options!(options)
click to toggle source
Validate that Vault
options are all a-okay! This method will raise exceptions if something does not make sense.
# File lib/vault/encrypted_model.rb, line 107 def _vault_validate_options!(options) if options[:serializer] if options[:encode] || options[:decode] raise Vault::Rails::ValidationFailedError, "Cannot use a " \ "custom encoder/decoder if a `:serializer' is specified!" end if options[:transform_secret] raise Vault::Rails::ValidationFailedError, "Cannot use the " \ "transform secrets engine with a specified `:serializer'!" end end if options[:encode] && !options[:decode] raise Vault::Rails::ValidationFailedError, "Cannot specify " \ "`:encode' without specifying `:decode' as well!" end if options[:decode] && !options[:encode] raise Vault::Rails::ValidationFailedError, "Cannot specify " \ "`:decode' without specifying `:encode' as well!" end if context = options[:context] if context.is_a?(Proc) && context.arity != 1 raise Vault::Rails::ValidationFailedError, "Proc passed to " \ "`:context' must take 1 argument!" end end if transform_opts = options[:transform_secret] if !transform_opts[:transformation] raise Vault::Rails::VaildationFailedError, "Transform Secrets " \ "requires a transformation name!" end end end
vault_attribute(attribute, options = {})
click to toggle source
Creates an attribute that is read and written using Vault
.
@example
class Person < ActiveRecord::Base include Vault::EncryptedModel vault_attribute :ssn end person = Person.new person.ssn = "123-45-6789" person.save person.encrypted_ssn #=> "vault:v0:6hdPkhvyL6..."
@param [Symbol] column
the column that is encrypted
@param [Hash] options
@option options [Symbol] :encrypted_column
the name of the encrypted column (default: +#{column}_encrypted+)
@option options [String] :path
the path to the transit backend (default: +transit+)
@option options [String] :key
the name of the encryption key (default: +#{app}_#{table}_#{column}+)
@option options [String, Symbol, Proc] :context
either a string context, or a symbol or proc used to generate a context for key generation
@option options [Object] :default
a default value for this attribute to be set to if the underlying value is nil
@option options [Symbol, Class] :serializer
the name of the serializer to use (or a class)
@option options [Proc] :encode
a proc to encode the value with
@option options [Proc] :decode
a proc to decode the value with
@option options [Hash] :transform_secret
a hash providing details about the transformation to use, this includes the name, and the role to use
Calls superclass method
# File lib/vault/encrypted_model.rb, line 50 def vault_attribute(attribute, options = {}) # Sanity check options! _vault_validate_options!(options) parsed_opts = if options[:transform_secret] parse_transform_secret_attributes(attribute, options) else parse_transit_attributes(attribute, options) end parsed_opts[:encrypted_column] = options[:encrypted_column] || "#{attribute}_encrypted" # Make a note of this attribute so we can use it in the future (maybe). __vault_attributes[attribute.to_sym] = parsed_opts self.attribute attribute.to_s, ActiveRecord::Type::Value.new, default: nil # Getter define_method("#{attribute}") do self.__vault_load_attributes!(attribute) unless @__vault_loaded super() end # Setter define_method("#{attribute}=") do |value| self.__vault_load_attributes!(attribute) unless @__vault_loaded # We always set it as changed without comparing with the current value # because we allow our held values to be mutated, so we need to assume # that if you call attr=, you want it sent back regardless. attribute_will_change!("#{attribute}") instance_variable_set("@#{attribute}", value) super(value) # Return the value to be consistent with other AR methods. value end # Checker define_method("#{attribute}?") do self.__vault_load_attributes!(attribute) unless @__vault_loaded instance_variable_get("@#{attribute}").present? end self end
vault_lazy_decrypt()
click to toggle source
# File lib/vault/encrypted_model.rb, line 144 def vault_lazy_decrypt @vault_lazy_decrypt ||= false end
vault_lazy_decrypt!()
click to toggle source
# File lib/vault/encrypted_model.rb, line 148 def vault_lazy_decrypt! @vault_lazy_decrypt = true end
vault_single_decrypt()
click to toggle source
# File lib/vault/encrypted_model.rb, line 152 def vault_single_decrypt @vault_single_decrypt ||= false end
vault_single_decrypt!()
click to toggle source
# File lib/vault/encrypted_model.rb, line 156 def vault_single_decrypt! @vault_single_decrypt = true end
Private Instance Methods
parse_transform_secret_attributes(attribute, options)
click to toggle source
# File lib/vault/encrypted_model.rb, line 162 def parse_transform_secret_attributes(attribute, options) opts = {} opts[:transform_secret] = true serializer = Class.new serializer.define_singleton_method(:encode) do |raw| return if raw.nil? resp = Vault::Rails.transform_encode(raw, options[:transform_secret]) resp.dig(:data, :encoded_value) end serializer.define_singleton_method(:decode) do |raw| return if raw.nil? resp = Vault::Rails.transform_decode(raw, options[:transform_secret]) resp.dig(:data, :decoded_value) end opts[:serializer] = serializer opts end
parse_transit_attributes(attribute, options)
click to toggle source
# File lib/vault/encrypted_model.rb, line 181 def parse_transit_attributes(attribute, options) opts = {} opts[:path] = options[:path] || "transit" opts[:key] = options[:key] || "#{Vault::Rails.application}_#{table_name}_#{attribute}" opts[:context] = options[:context] opts[:default] = options[:default] # Get the serializer if one was given. serializer = options[:serialize] # Unless a class or module was given, construct our serializer. (Slass # is a subset of Module). if serializer && !serializer.is_a?(Module) serializer = Vault::Rails.serializer_for(serializer) end # See if custom encoding or decoding options were given. if options[:encode] && options[:decode] serializer = Class.new serializer.define_singleton_method(:encode, &options[:encode]) serializer.define_singleton_method(:decode, &options[:decode]) end opts[:serializer] = serializer opts end