I'm trying to add an encrypted jsonb field to my user model in rails. I'm getting an error when attempting to read or set a value.
error
irb(main):002:0> User.last.q2_email_address = "[email protected]"
User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
Encrypt Data Key (190.1ms) Context: {:model_name=>"User", :model_id=>11}
/Users/antarr/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0/gems/encryptor-3.0.0/lib/encryptor.rb:61:in `crypt': must specify an iv (ArgumentError)
user.rb
has_kms_key eager_encrypt: :fetch_id
attr_encrypted :settings, key: :kms_key, mashall: true
store :settings,
accessors: [:address1, :address2, :city, :customer_id, :customer_name, :customer_primary_cif, :social_security_number,
:email_address, :first_name, :group_desc, :group_id, :home_phone, :aba, :hq_session_id, :language, :last_name,
:login_name, :middle_name, :mobile_phone, :postal_code, :ssn, :state, :user_logon_id, :user_id, :user_primary_cif,
:work_phone, :ip_address, :token], coder: JSON, prefix: :q2
migration
def up
add_column :users, :encrypted_kms_key, :text
add_column :users, :encrypted_settings, :jsonb, null: false, default: '{}'
add_column :users, :encrypted_settings_iv, :string
add_index :users, :encrypted_settings, using: :gin
end
config/initializer/aws.rb
Aws.config[:credentials] = Aws::Credentials.new(
ENV['AMAZON_ACCESS_KEY'],
ENV['AMAZON_SECRET_KEY']
)
Gemfile
gem 'attr_encrypted' # 3.1.0
gem 'aws-sdk-kms'
gem 'kms_encrypted'
there're 2 method
encrypt
in the gemattr_encrypted
, one is class method and one is instance method, the instance method will automatically generaterandom iv
, meanwhile the class method will not, it uses theiv
you setup.when you call
User.last.q2_email_address = "[email protected]"
, this method will call the class methodencrypt
, the instance method will not be called, so that if you don't setupiv
, the errormust specify an iv (ArgumentError)
will be raised.there's 2 ways to fix, the first one is setup the
iv
unfortunately, another error will be raised (relate to
iv_len
) and i'm still not figure out the root cause and fix it.the second way: copy this method into the model so that the instance method
encrypt
will be called, a randomiv
will be generated, and it works.however, in case of
store attributes
, it does not saveencrypted attribute
, for exampleso i came up with an idea that we can create a module support
store attributes
as below