Skip to content

Commit

Permalink
Filter encrypted attributes automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
vlad-psh committed Jul 5, 2022
1 parent 39d29e2 commit a74d7e4
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 11 deletions.
42 changes: 31 additions & 11 deletions lib/audited/auditor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ def revision_at(date_or_time)
# List of attributes that are audited.
def audited_attributes
audited_attributes = attributes.except(*self.class.non_audited_columns)
audited_attributes = redact_values(audited_attributes)
audited_attributes = filter_encrypted_attrs(audited_attributes)
normalize_enum_changes(audited_attributes)
end

Expand Down Expand Up @@ -234,6 +236,7 @@ def audited_changes
end

filtered_changes = redact_values(filtered_changes)
filtered_changes = filter_encrypted_attrs(filtered_changes)
filtered_changes = normalize_enum_changes(filtered_changes)
filtered_changes.to_hash
end
Expand All @@ -257,19 +260,36 @@ def normalize_enum_changes(changes)
end

def redact_values(filtered_changes)
[audited_options[:redacted]].flatten.compact.each do |option|
changes = filtered_changes[option.to_s]
new_value = audited_options[:redaction_value] || REDACTED
values = if changes.is_a? Array
changes.map { new_value }
else
new_value
end
hash = {option.to_s => values}
filtered_changes.merge!(hash)
filter_attr_values(
audited_changes: filtered_changes,
attrs: Array(audited_options[:redacted]).map(&:to_s),
placeholder: audited_options[:redaction_value] || REDACTED,
)
end

def filter_encrypted_attrs(filtered_changes)
filter_attr_values(
audited_changes: filtered_changes,
attrs: respond_to?(:encrypted_attributes) ? Array(encrypted_attributes).map(&:to_s) : [],
)
end

# Replace values for given attrs to a placeholder and return modified hash
#
# @param audited_changes [Hash] Hash of changes to be saved to audited version record
# @param attrs [Array<String>] Array of attrs, values of which will be replaced to placeholder value
# @param placeholder [String] Placeholder to replace original attr values
def filter_attr_values(audited_changes: {}, attrs: [], placeholder: '[FILTERED]')
attrs.each do |attr|
next unless audited_changes.key?(attr)

changes = audited_changes[attr]
values = changes.is_a?(Array) ? changes.map { placeholder } : placeholder

audited_changes[attr] = values
end

filtered_changes
audited_changes
end

def rails_below?(rails_version)
Expand Down
6 changes: 6 additions & 0 deletions spec/audited/auditor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ def non_column_attr=(val)
expect(user.audits.last.audited_changes["password"]).to eq(["My", "Custom", "Value", 7])
end

it "should filter encrypted attributes" do
user = Models::ActiveRecord::UserWithEncryptedPassword.create(password: "password")
user.save
expect(user.audits.last.audited_changes["password"]).to eq("[FILTERED]")
end

if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
describe "'json' and 'jsonb' audited_changes column type" do
let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
Expand Down
3 changes: 3 additions & 0 deletions spec/rails_app/config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@

# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true

config.active_record.encryption.key_derivation_salt = SecureRandom.hex
config.active_record.encryption.primary_key = SecureRandom.hex
end
6 changes: 6 additions & 0 deletions spec/support/active_record/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class UserRedactedPasswordCustomRedaction < ::ActiveRecord::Base
audited redacted: :password, redaction_value: ["My", "Custom", "Value", 7]
end

class UserWithEncryptedPassword < ::ActiveRecord::Base
self.table_name = :users
audited
encrypts :password
end

class CommentRequiredUser < ::ActiveRecord::Base
self.table_name = :users
audited except: :password, comment_required: true
Expand Down

0 comments on commit a74d7e4

Please sign in to comment.