lib/lockbox/model.rb in lockbox-0.2.4 vs lib/lockbox/model.rb in lockbox-0.2.5
- old
+ new
@@ -102,14 +102,17 @@
raise "Duplicate encrypted attribute: #{original_name}" if lockbox_attributes[original_name]
@lockbox_attributes[original_name] = options.merge(encode: encode)
if @lockbox_attributes.size == 1
+ # use same approach as activerecord serialization
def serializable_hash(options = nil)
options = options.try(:dup) || {}
+
options[:except] = Array(options[:except])
- options[:except] += self.class.lockbox_attributes.values.flat_map { |v| [v[:attribute], v[:encrypted_attribute]] }
+ options[:except] += self.class.lockbox_attributes.flat_map { |_, v| [v[:attribute], v[:encrypted_attribute]] }
+
super(options)
end
# use same approach as devise
def inspect
@@ -149,10 +152,14 @@
serialize name, JSON if options[:type] == :json
serialize name, Hash if options[:type] == :hash
if respond_to?(:attribute)
attribute name, attribute_type
+
+ define_method("#{name}?") do
+ send("#{encrypted_attribute}?")
+ end
else
m = Module.new do
define_method("#{name}=") do |val|
prev_val = instance_variable_get("@#{name}")
@@ -181,64 +188,20 @@
end
define_method("#{name}=") do |message|
original_message = message
- unless message.nil?
- 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?
- when :date
- message = ActiveRecord::Type::Date.new.serialize(message)
- # strftime should be more stable than to_s(:db)
- message = message.strftime("%Y-%m-%d") unless message.nil?
- when :datetime
- message = ActiveRecord::Type::DateTime.new.serialize(message)
- message = nil unless message.respond_to?(:iso8601) # for Active Record < 5.2
- message = message.iso8601(9) unless message.nil?
- when :time
- message = ActiveRecord::Type::Time.new.serialize(message)
- message = nil unless message.respond_to?(:strftime)
- message = message.strftime("%H:%M:%S.%N") unless message.nil?
- message
- when :integer
- message = ActiveRecord::Type::Integer.new(limit: 8).serialize(message)
- message = 0 if message.nil?
- # signed 64-bit integer, big endian
- message = [message].pack("q>")
- when :float
- message = ActiveRecord::Type::Float.new.serialize(message)
- # double precision, big endian
- message = [message].pack("G") unless message.nil?
- when :string, :binary
- # do nothing
- # encrypt will convert to binary
- else
- type = (self.class.try(:attribute_types) || {})[name.to_s]
- if type && type.is_a?(ActiveRecord::Type::Serialized)
- message = type.serialize(message)
- end
- end
- end
-
# decrypt first for dirty tracking
# don't raise error if can't decrypt previous
begin
send(name)
rescue Lockbox::DecryptionError
nil
end
- ciphertext =
- if message.nil? || (message == "" && !options[:padding])
- message
- else
- self.class.send(class_method_name, message, context: self)
- end
-
+ # set ciphertext
+ ciphertext = self.class.send(class_method_name, message, context: self)
send("#{encrypted_attribute}=", ciphertext)
super(original_message)
end
@@ -303,12 +266,56 @@
end
# for fixtures
define_singleton_method class_method_name do |message, **opts|
table = respond_to?(:table_name) ? table_name : collection_name.to_s
- ciphertext = Lockbox::Utils.build_box(opts[:context], options, table, encrypted_attribute).encrypt(message)
- ciphertext = Base64.strict_encode64(ciphertext) if encode
- ciphertext
+
+ unless message.nil?
+ 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?
+ when :date
+ message = ActiveRecord::Type::Date.new.serialize(message)
+ # strftime should be more stable than to_s(:db)
+ message = message.strftime("%Y-%m-%d") unless message.nil?
+ when :datetime
+ message = ActiveRecord::Type::DateTime.new.serialize(message)
+ message = nil unless message.respond_to?(:iso8601) # for Active Record < 5.2
+ message = message.iso8601(9) unless message.nil?
+ when :time
+ message = ActiveRecord::Type::Time.new.serialize(message)
+ message = nil unless message.respond_to?(:strftime)
+ message = message.strftime("%H:%M:%S.%N") unless message.nil?
+ message
+ when :integer
+ message = ActiveRecord::Type::Integer.new(limit: 8).serialize(message)
+ message = 0 if message.nil?
+ # signed 64-bit integer, big endian
+ message = [message].pack("q>")
+ when :float
+ message = ActiveRecord::Type::Float.new.serialize(message)
+ # double precision, big endian
+ message = [message].pack("G") unless message.nil?
+ when :string, :binary
+ # do nothing
+ # encrypt will convert to binary
+ else
+ type = (try(:attribute_types) || {})[name.to_s]
+ if type && type.is_a?(ActiveRecord::Type::Serialized)
+ message = type.serialize(message)
+ end
+ end
+ end
+
+ if message.nil? || (message == "" && !options[:padding])
+ message
+ else
+ ciphertext = Lockbox::Utils.build_box(opts[:context], options, table, encrypted_attribute).encrypt(message)
+ ciphertext = Base64.strict_encode64(ciphertext) if encode
+ ciphertext
+ end
end
end
end
end
end