attr-encrypted / attr_encrypted

Generates attr_accessors that encrypt and decrypt attributes
MIT License
2.01k stars 427 forks source link

attr_encrypted / ActiveRecord problem w. rack #166

Open nesrual opened 9 years ago

nesrual commented 9 years ago

I am using attr_encrypted from a rack/ruby script and it seems like there is some weird issue with ActiveRecord and attr_encrypted.

attr_encrypted works fine and the correct values are set in the object. The object is validated using ActiveModel, however when saving the object the values set by attr_encrypted are cleared (nil).

It works fine using the console and the object is saved to the database.

Using Ruby 2.2.2, Rails 4.2.2, PostgreSQL

Code example below to replicate the problem:

require 'attr_encrypted'
require 'active_model'
require 'active_record'

KEY = 'top secret'

# Our env

ENV["RAILS_ENV"] ||= "development"

# Our secret key

VAULT_ENTRY_KEY = 'secret'

# Model

require ::File.expand_path('./app/models/vault_entry.rb')

# Contents of vault_entry.rb

=begin
class VaultEntry < ActiveRecord::Base

  # Read only attributes

  attr_readonly :id, :created_at

  # Our encrypted attribute

  attr_encrypted :data, :key => VAULT_ENTRY_KEY, :mode => :per_attribute_iv_and_salt, :encode => true, :type => :string, :random_iv => true

  # Validations

  validates_presence_of :data, :encrypted_data_salt, :encrypted_data_iv

end
=end

# Migration for vault_entry (using schema_plus)

=begin
class CreateVaultEntries < ActiveRecord::Migration
  def change
    create_table :vault_entries, id: :uuid do |t|
      t.string :encrypted_data, null: false
      t.string :encrypted_data_salt, null: false
      t.string :encrypted_data_iv, null: false
      t.timestamps null: false
    end
  end
end
=end 

# Connect to the database

dbconfig = YAML::load(File.open('./config/database.yml'))
ActiveRecord::Base.establish_connection(dbconfig[ENV["RAILS_ENV"]])

entry = VaultEntry.new(:data => 'test')

# Examine the entry object

puts "DATA: #{entry.data}"
puts "ENCRYPTED_DATA: #{entry.encrypted_data}"
puts "ENCRYPTED_DATA_SALT: #{entry.encrypted_data_salt}"
puts "ENCRYPTED_DATA_IV: #{entry.encrypted_data_iv}"

# Is the object valid?

puts "Is the object valid? #{entry.valid?}"

=begin
DATA: test
ENCRYPTED_DATA: 6NBLFaaW415KIUNAaLQ19Q==
ENCRYPTED_DATA_SALT: 6851b995345ac0da
ENCRYPTED_DATA_IV: 7m8qT/JetxS1lOjyL751UA==
Is the object valid? true
=end

# Try to save the entry

entry.save

# Boom!

=begin
activerecord-4.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:602:in `exec_prepared': PG::NotNullViolation: ERROR:  null value in column "encrypted_data" violates not-null constraint (ActiveRecord::StatementInvalid)
DETAIL:  Failing row contains (b1ce54e6-9be2-41a6-a3c8-61d076f72b80, null, null, null, 2015-06-17 17:59:17.706087, 2015-06-17 17:59:17.706087).
: INSERT INTO "vault_entries" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"
=end
jarlos3 commented 1 year ago

It's been a while... :)

but since the issue is still open, I think the problem is not with Rack. I think the solution to your problem is to first require active_record and active_model before attr_encrypted.

require 'active_record'
require 'active_model'
require 'attr_encrypted'

The ActiveRecord adapter will load only if ActiveRecord::Base was defined.

https://github.com/attr-encrypted/attr_encrypted/blob/master/lib/attr_encrypted/adapters/active_record.rb#L3