From 470dca307c7548b127364081b63776bdac18545b Mon Sep 17 00:00:00 2001 From: Sridhar Date: Mon, 15 Jan 2024 17:49:23 +0530 Subject: [PATCH 1/4] New configurable settings: encryption for audited_changes & filtering encrypted attrs --- lib/audited.rb | 4 ++++ lib/audited/audit.rb | 4 ++++ lib/audited/auditor.rb | 6 ++++++ spec/audited/audit_spec.rb | 18 ++++++++++++++++++ spec/audited/auditor_spec.rb | 14 +++++++++++++- spec/support/active_record/models.rb | 3 +++ 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/audited.rb b/lib/audited.rb index 47559ade..faa49102 100644 --- a/lib/audited.rb +++ b/lib/audited.rb @@ -8,6 +8,8 @@ class << self attr_accessor \ :auditing_enabled, :current_user_method, + :encrypt_audited_changes, + :filter_encrypted_attributes, :ignored_attributes, :ignored_default_callbacks, :max_audits, @@ -40,6 +42,8 @@ def config @current_user_method = :current_user @auditing_enabled = true + @encrypt_audited_changes = false + @filter_encrypted_attributes = true @store_synthesized_enums = false end diff --git a/lib/audited/audit.rb b/lib/audited/audit.rb index 54a51f18..899ee2b0 100644 --- a/lib/audited/audit.rb +++ b/lib/audited/audit.rb @@ -55,6 +55,10 @@ class Audit < ::ActiveRecord::Base serialize :audited_changes, YAMLIfTextColumnType end + if Rails.gem_version >= Gem::Version.new("7.0") && Audited.encrypt_audited_changes + encrypts :audited_changes + end + scope :ascending, -> { reorder(version: :asc) } scope :descending, -> { reorder(version: :desc) } scope :creates, -> { where(action: "create") } diff --git a/lib/audited/auditor.rb b/lib/audited/auditor.rb index 9fd90092..07c5b8aa 100644 --- a/lib/audited/auditor.rb +++ b/lib/audited/auditor.rb @@ -289,6 +289,8 @@ def redact_values(filtered_changes) end def filter_encrypted_attrs(filtered_changes) + return filtered_changes unless filter_encrypted_attributes? + filter_attr_values( audited_changes: filtered_changes, attrs: respond_to?(:encrypted_attributes) ? Array(encrypted_attributes).map(&:to_s) : [] @@ -420,6 +422,10 @@ def reconstruct_attributes(audits) audits.each { |audit| attributes.merge!(audit.new_attributes) } attributes end + + def filter_encrypted_attributes? + Audited.filter_encrypted_attributes + end end module AuditedClassMethods diff --git a/spec/audited/audit_spec.rb b/spec/audited/audit_spec.rb index c18abdb5..21d67dae 100644 --- a/spec/audited/audit_spec.rb +++ b/spec/audited/audit_spec.rb @@ -74,6 +74,24 @@ class Models::ActiveRecord::CustomUserSubclass < Models::ActiveRecord::CustomUse audit.audited_changes = {foo: "bar"} expect(audit.audited_changes).to eq "{:foo=>\"bar\"}" end + + if ::ActiveRecord::VERSION::MAJOR >= 7 + context "when encryption is enabled" do + before do + Audited.encrypt_audited_changes = true + end + + it "encrypts the whole column" do + company = Models::ActiveRecord::EncryptCompanyAuditedChanges.create!(name: "CollectiveIdea") + + audit = company.audits.last + audited_changes = audit.audited_changes + + expect({"name"=>"CollectiveIdea", "owner_id"=>nil}).not_to eq(audit.ciphertext_for(:audited_changes)) + expect({"name"=>"CollectiveIdea", "owner_id"=>nil}).to eq(audited_changes) + end + end + end end describe "#undo" do diff --git a/spec/audited/auditor_spec.rb b/spec/audited/auditor_spec.rb index 72f71fa0..4bf2b870 100644 --- a/spec/audited/auditor_spec.rb +++ b/spec/audited/auditor_spec.rb @@ -267,11 +267,23 @@ class CallbacksSpecified < ::ActiveRecord::Base end if ::ActiveRecord::VERSION::MAJOR >= 7 - it "should filter encrypted attributes" do + it "should filter encrypted attributes by default" do user = Models::ActiveRecord::UserWithEncryptedPassword.create(password: "password") user.save expect(user.audits.last.audited_changes["password"]).to eq("[FILTERED]") end + + context "when filtering is disabled" do + before do + Audited.filter_encrypted_attributes = false + end + + it "should not filter encrypted attributes" do + user = Models::ActiveRecord::UserWithEncryptedPassword.create(password: "password") + user.save + expect(user.audits.last.audited_changes["password"]).not_to eq("[FILTERED]") + end + end end if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" diff --git a/spec/support/active_record/models.rb b/spec/support/active_record/models.rb index 6e50b552..bd4b4d0c 100644 --- a/spec/support/active_record/models.rb +++ b/spec/support/active_record/models.rb @@ -127,6 +127,9 @@ class Company < ::ActiveRecord::Base audited end + class EncryptCompanyAuditedChanges < Company + end + class Company::STICompany < Company end From 424fcfce3d4f61777c437d54019e87d244a1982d Mon Sep 17 00:00:00 2001 From: Sridhar Date: Mon, 15 Jan 2024 18:07:06 +0530 Subject: [PATCH 2/4] Update README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 22ce14c9..454c701d 100644 --- a/README.md +++ b/README.md @@ -403,6 +403,17 @@ class User < ActiveRecord::Base end ``` +You can disable the filtering by adding a config + +```ruby +Audited.filter_encrypted_attributes = false +``` + +If you want to encrypt the changes that are audited, you can simply add this line to your config +```ruby +Audited.encrypt_audited_changes = true +``` + ### Custom `Audit` model If you want to extend or modify the audit model, create a new class that From 13fd6b3bbdff8b7c3c1c2cae06c1581599a36ed8 Mon Sep 17 00:00:00 2001 From: Sridhar Date: Mon, 15 Jan 2024 23:20:06 +0530 Subject: [PATCH 3/4] Add additional 3 lines to uncovered --- spec/audited/audit_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/audited/audit_spec.rb b/spec/audited/audit_spec.rb index 21d67dae..72a8569f 100644 --- a/spec/audited/audit_spec.rb +++ b/spec/audited/audit_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -SingleCov.covered! uncovered: 2 # Rails version check +SingleCov.covered! uncovered: 5 # Rails version check class CustomAudit < Audited::Audit def custom_method From ce0b63ad82cf291c5d6ba72af59bc028cdb103ee Mon Sep 17 00:00:00 2001 From: Sridhar Date: Tue, 30 Jan 2024 16:06:47 +0530 Subject: [PATCH 4/4] Update uncovered lines --- spec/audited/auditor_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/audited/auditor_spec.rb b/spec/audited/auditor_spec.rb index 4bf2b870..a7b448ba 100644 --- a/spec/audited/auditor_spec.rb +++ b/spec/audited/auditor_spec.rb @@ -2,7 +2,7 @@ # not testing proxy_respond_to? hack / 2 methods / deprecation of `version` # also, an additional 6 around `after_touch` for Versions before 6. -uncovered = (ActiveRecord::VERSION::MAJOR < 6) ? 15 : 9 +uncovered = (ActiveRecord::VERSION::MAJOR < 6) ? 16 : 9 SingleCov.covered! uncovered: uncovered class ConditionalPrivateCompany < ::ActiveRecord::Base