Skip to content

Commit

Permalink
Improved attributes, attribute_names, and has_attribute? when ciphert…
Browse files Browse the repository at this point in the history
…ext attribute not loaded
  • Loading branch information
ankane committed Oct 23, 2024
1 parent b3d1dcc commit 89faa9c
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 2.0.0 (unreleased)

- Improved `attributes`, `attribute_names`, and `has_attribute?` when ciphertext attribute not loaded
- Dropped support for Active Record < 7 and Ruby < 3.1
- Dropped support for Mongoid < 8

Expand Down
35 changes: 34 additions & 1 deletion lib/lockbox/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,40 @@ def attributes
end
end
end
super

# remove attributes that do not have a ciphertext attribute
attributes = super
self.class.lockbox_attributes.each do |k, lockbox_attribute|
if !attributes.include?(lockbox_attribute[:encrypted_attribute].to_s)
attributes.delete(k.to_s)
attributes.delete(lockbox_attribute[:attribute])
end
end
attributes
end

# remove attribute names that do not have a ciphertext attribute
def attribute_names
# hash preserves key order
names_set = super.to_h { |v| [v, true] }
self.class.lockbox_attributes.each do |k, lockbox_attribute|
if !names_set.include?(lockbox_attribute[:encrypted_attribute].to_s)
names_set.delete(k.to_s)
names_set.delete(lockbox_attribute[:attribute])
end
end
names_set.keys
end

# check the ciphertext attribute for encrypted attributes
def has_attribute?(attr_name)
attr_name = attr_name.to_s
_, lockbox_attribute = self.class.lockbox_attributes.find { |_, la| la[:attribute] == attr_name }
if lockbox_attribute
super(lockbox_attribute[:encrypted_attribute])
else
super
end
end

# needed for in-place modifications
Expand Down
11 changes: 4 additions & 7 deletions test/model_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,10 @@ def test_attributes_not_loaded
assert !user.has_attribute?("name")
assert !user.has_attribute?(:name)

# TODO try to make virtual attribute behavior consistent
# this may be difficult, as virtual attributes are set to self.class._default_attributes
# which gets merged with query attributes in initialize method of active_record/core.rb
# assert_equal ["id"], user.attributes.keys
# assert_equal ["id"], user.attribute_names
# assert !user.has_attribute?("email")
# assert !user.has_attribute?(:email)
assert_equal ["id"], user.attributes.keys
assert_equal ["id"], user.attribute_names
assert !user.has_attribute?("email")
assert !user.has_attribute?(:email)

user = User.select("id AS email_ciphertext").last
assert_raises(Lockbox::DecryptionError) do
Expand Down

0 comments on commit 89faa9c

Please sign in to comment.