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)