module KmsRails::ActiveRecord::ClassMethods

Public Instance Methods

kms_attr(field, key_id:, retain: false, msgpack: false, context_key: nil, context_value: nil) click to toggle source
# File lib/kms_rails/active_record.rb, line 13
def kms_attr(field, key_id:, retain: false, msgpack: false, context_key: nil, context_value: nil)
  include InstanceMethods

  real_field = "#{field}_enc"
  enc        = Core.new(key_id: key_id, msgpack: msgpack, context_key: context_key, context_value: context_value)

  define_method "#{field}=" do |data|
    raise RuntimeError, "Field '#{field}' must not be a real column, '#{real_field}' is the real column" if self.class.column_names.include?(field.to_s)
    raise RuntimeError, "Field '#{real_field}' must exist to store encrypted data" unless self.class.column_names.include?(real_field)

    if data.blank? # Just set to nil if nil
      clear_retained(field)
      self[real_field] = nil
      return 
    end

    set_retained(field, data) if retain
    encrypted_data = enc.encrypt(data)
    data = nil
    
    store_hash(field, encrypted_data)
  end

  define_method "#{real_field}" do
    raise RuntimeError, "Field '#{field}' must not be a real column, '#{real_field}' is the real column" if self.class.column_names.include?(field.to_s)
    raise RuntimeError, "Field '#{real_field}' must exist to retrieve encrypted data" unless self.class.column_names.include?(real_field)
    Core.to64( get_hash(field) )
  end

  define_method "#{field}" do
    raise RuntimeError, "Field '#{field}' must not be a real column, '#{real_field}' is the real column" if self.class.column_names.include?(field.to_s)
    raise RuntimeError, "Field '#{real_field}' must exist to retrieve decrypted data" unless self.class.column_names.include?(real_field)

    hash = get_hash(field)
    return nil unless hash

    if retain && (plaintext = get_retained(field))
      plaintext
    else
      plaintext = enc.decrypt(hash)
      set_retained(field, plaintext) if retain
      plaintext
    end
  end

  define_method "#{field}_clear" do
    clear_retained(field)
  end

end