ankane / lockbox

Modern encryption for Ruby and Rails
MIT License
1.44k stars 68 forks source link

Cannot get simple getter overrides to work, infinite loop issues #117

Closed x9sim9 closed 3 years ago

x9sim9 commented 3 years ago
encrypts :my_field

# causes infinite loop
def my_field
  self[:my_field]
end

# returns blank
def my_field
  super
end

using self causes infinite loop issue and using super returns blank

ankane commented 3 years ago

Hey @x9sim9, overriding Lockbox methods isn't supported, but the 2nd approach will likely work if you combine it with Module#prepend.

x9sim9 commented 3 years ago

Hey @x9sim9, overriding Lockbox methods isn't supported, but the 2nd approach will likely work if you combine it with Module#prepend.

I may be confused but wouldn't prepend run before decrypting the field whereas I want to modify the data after its been decrypted?

x9sim9 commented 3 years ago

For my use case I was integrating lockbox into an existing code base so it was not practical to rewrite the codebase, I did however manage to solve the infinite loop issue with self using your idea, could this fix be applied into the gem?

module Self
    def [](key)
        new_key = (key.to_s + "_ciphertext").to_sym
        decrypt_method = ("decrypt_" + key.to_s + "_ciphertext").to_sym

        if self.class.methods.include?(decrypt_method)
            return self.class.send(decrypt_method, self.send(new_key))
        end

        super(key)
    end
end

class MyModel < ActiveRecord::Base
    prepend Self

end

Especially considering the infinite loop issue,

many thanks, Simon

ankane commented 3 years ago

The infinite loop is due to how it's being overridden. You'll want to do something like:

module MyModelOverride
  def my_field
    value = super
    # do something with value
  end
end

class MyModel < ActiveRecord::Base
  prepend MyModelOverride
  encrypts :my_field
end
x9sim9 commented 3 years ago

The infinite loop is due to how it's being overridden. You'll want to do something like:

module MyModelOverride
  def my_field
    value = super
    # do something with value
  end
end

class MyModel < ActiveRecord::Base
  prepend MyModelOverride
  encrypts :my_field
end

Hi the code I posted in the previous comment works perfectly I was just referencing your earlier comment "Overiding Lockbox Methods is not supported" if you integrated my suggestion or something similar then it would be supported for everyone, but thanks to your suggestion I now have a project wide fix as posted in the previous comment. Many thanks for the help, simon

ankane commented 3 years ago

Glad it's working, and thanks for sharing it. I think the gem would use a different approach to support overriding Lockbox methods directly in models, but it's not something I'd like to support right now.