lib/lockbox/model.rb in lockbox-0.5.0 vs lib/lockbox/model.rb in lockbox-0.6.0
- old
+ new
@@ -53,10 +53,19 @@
encrypt_method_name = "generate_#{encrypted_attribute}"
decrypt_method_name = "decrypt_#{encrypted_attribute}"
class_eval do
+ # Lockbox uses custom inspect
+ # but this could be useful for other gems
+ if activerecord && ActiveRecord::VERSION::MAJOR >= 6
+ # only add virtual attribute
+ # need to use regexp since strings do partial matching
+ # also, need to use += instead of <<
+ self.filter_attributes += [/\A#{Regexp.escape(options[:attribute])}\z/]
+ end
+
@lockbox_attributes ||= {}
if @lockbox_attributes.empty?
def self.lockbox_attributes
parent_attributes =
@@ -77,19 +86,44 @@
options[:except] += self.class.lockbox_attributes.flat_map { |_, v| [v[:attribute], v[:encrypted_attribute]] }
super(options)
end
- # use same approach as devise
+ # maintain order
+ # replace ciphertext attributes w/ virtual attributes (filtered)
def inspect
- inspection =
- serializable_hash.map do |k,v|
- "#{k}: #{respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : v.inspect}"
+ lockbox_attributes = {}
+ lockbox_encrypted_attributes = {}
+ self.class.lockbox_attributes.each do |_, lockbox_attribute|
+ lockbox_attributes[lockbox_attribute[:attribute]] = true
+ lockbox_encrypted_attributes[lockbox_attribute[:encrypted_attribute]] = lockbox_attribute[:attribute]
+ end
+
+ inspection = []
+ # use serializable_hash like Devise
+ values = serializable_hash
+ self.class.attribute_names.each do |k|
+ next if !has_attribute?(k) || lockbox_attributes[k]
+
+ # check for lockbox attribute
+ if lockbox_encrypted_attributes[k]
+ # check if ciphertext attribute nil to avoid loading attribute
+ v = send(k).nil? ? "nil" : "[FILTERED]"
+ k = lockbox_encrypted_attributes[k]
+ elsif values.key?(k)
+ v = respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : values[k].inspect
+
+ # fix for https://github.com/rails/rails/issues/40725
+ # TODO only apply to Active Record 6.0
+ if respond_to?(:inspection_filter, true) && v != "nil"
+ v = inspection_filter.filter_param(k, v)
+ end
+ else
+ next
end
- self.class.lockbox_attributes.map do |_, lockbox_attribute|
- inspection << "#{lockbox_attribute[:attribute]}: [FILTERED]" if has_attribute?(lockbox_attribute[:encrypted_attribute])
+ inspection << "#{k}: #{v}"
end
"#<#{self.class} #{inspection.join(", ")}>"
end
@@ -350,11 +384,11 @@
# for fixtures
define_singleton_method encrypt_method_name do |message, **opts|
table = activerecord ? table_name : collection_name.to_s
unless message.nil?
- # TODO use attribute type class in 0.6.0
+ # TODO use attribute type class in 0.7.0
case options[:type]
when :boolean
message = ActiveRecord::Type::Boolean.new.serialize(message)
message = nil if message == "" # for Active Record < 5.2
message = message ? "t" : "f" unless message.nil?
@@ -405,10 +439,10 @@
table = activerecord ? table_name : collection_name.to_s
Lockbox::Utils.build_box(opts[:context], options, table, encrypted_attribute).decrypt(ciphertext)
end
unless message.nil?
- # TODO use attribute type class in 0.6.0
+ # TODO use attribute type class in 0.7.0
case options[:type]
when :boolean
message = message == "t"
when :date
message = ActiveRecord::Type::Date.new.deserialize(message)