My client wants all user data encrypted, so I've created a before_save
and after_find
call back that will encrypt certain properties using Gibberish
:
# user.rb
before_save UserEncryptor.new
after_find UserEncryptor.new
# user_encryptor.rb
class UserEncryptor
def initialize
@cipher = Gibberish::AES.new("password")
end
def before_save(user)
user.first_name = encrypt(user.first_name)
user.last_name = encrypt(user.last_name)
user.email = encrypt(user.email) unless not user.confirmed? or user.unconfirmed_email
end
def after_find(user)
user.first_name = decrypt(user.first_name)
user.last_name = decrypt(user.last_name)
user.email = decrypt(user.email) unless not user.confirmed? or user.unconfirmed_email
end
private
def encrypt(value)
@cipher.enc(value)
end
def decrypt(value)
@cipher.dec(value)
end
end
Well, when the user first signs up using Devise
, the model looks about like it should. But then once the user confirms, if I inspect the user, the first_name
and last_name
properties look to have been encrypted multiple times. So I put a breakpoint in the before_save
method and click the confirmation link, and I see that it's getting executed three times in a row. The result is that the encrypted value gets encrypted again, and then again, so next time we retrieve the record, and every time thereafter, we get a twice encrypted value.
Now, why the heck is this happening? It's not occurring for other non-devise models that are executing the same logic. Does Devise
have the current_user
cached in a few different places, and it saves the user in each location? How else could a before_save
callback be called 3 times before the next before_find
is executed?
And, more importantly, how can I successfully encrypt my user data when I'm using Devise
? I've also had problems with attr_encrypted
and devise_aes_encryptable
so if I get a lot of those suggestions then I guess I have some more questions to post :-)