Module: AttrRedactor
- Defined in:
- lib/attr_redactor.rb,
lib/attr_redactor/version.rb,
lib/attr_redactor/adapters/data_mapper.rb,
lib/attr_redactor/adapters/active_record.rb
Overview
Adds attr_accessors that redact an object’s attributes
Defined Under Namespace
Modules: Adapters, InstanceMethods, Version
Class Method Summary collapse
-
.extended(base) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#attr_redacted?(attribute) ⇒ Boolean
Checks if an attribute is configured with
attr_redactor
. -
#attr_redactor(*attributes) ⇒ Object
Generates attr_accessors that remove, digest or encrypt values in an attribute that is a hash transparently.
-
#attr_redactor_options ⇒ Object
Default options to use with calls to
attr_redactor
. -
#method_missing(method, *arguments, &block) ⇒ Object
Forwards calls to :redact_#attribute or :unredact_#attribute to the corresponding redact or unredact method if attribute was configured with attr_redactor.
-
#redact(attribute, value, options = {}) ⇒ Object
Redacts for the attribute specified.
-
#redacted_attributes ⇒ Object
Contains a hash of redacted attributes with virtual attribute names as keys and their corresponding options as values.
-
#unredact(attribute, redacted_value, options = {}) ⇒ Object
Decrypts values in the attribute specified.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *arguments, &block) ⇒ Object
Forwards calls to :redact_#attribute or :unredact_#attribute to the corresponding redact or unredact method if attribute was configured with attr_redactor
Example
class User
attr_redactor :data, key: 'my secret key'
end
User.redact_data('SOME_ENCRYPTED_EMAIL_STRING')
229 230 231 232 233 234 235 |
# File 'lib/attr_redactor.rb', line 229 def method_missing(method, *arguments, &block) if method.to_s =~ /^(redact|unredact)_(.+)$/ && attr_redacted?($2) send($1, $2, *arguments) else super end end |
Class Method Details
.extended(base) ⇒ Object
:nodoc:
7 8 9 10 11 12 13 |
# File 'lib/attr_redactor.rb', line 7 def self.extended(base) # :nodoc: base.class_eval do include InstanceMethods attr_writer :attr_redactor_options @attr_redactor_options, @redacted_attributes = {}, {} end end |
Instance Method Details
#attr_redacted?(attribute) ⇒ Boolean
Checks if an attribute is configured with attr_redactor
Example
class User
attr_accessor :name
attr_redactor :email
end
User.attr_redacted?(:name) # false
User.attr_redacted?(:email) # true
164 165 166 |
# File 'lib/attr_redactor.rb', line 164 def attr_redacted?(attribute) redacted_attributes.has_key?(attribute.to_sym) end |
#attr_redactor(*attributes) ⇒ Object
Generates attr_accessors that remove, digest or encrypt values in an attribute that is a hash transparently
Options Any other options you specify are passed on to hash_redactor which is used for redacting, and in turn onto attr_encrypted which it uses for encryption)
redact: Hash that describes the values to redact in the hash. Should be a
map of the form { key => method }, where key is the key to redact and method is one of :remove, :digest, :encrypt eg { :ssn => :remove, :email => :digest :medical_notes => :encrypt, }
attribute: The name of the referenced encrypted attribute. For example
<tt>attr_accessor :data, attribute: :safe_data</tt> would generate
an attribute named 'safe_data' to store the redacted data.
This is useful when defining one attribute to encrypt at a time or when the :prefix and :suffix options aren’t enough.
Defaults to nil.
prefix: A prefix used to generate the name of the referenced redacted attributes.
For example <tt>attr_accessor :data, prefix: 'safe_'</tt> would
generate attributes named 'safe_data' to store the redacted
data hash.
Defaults to 'redacted_'.
suffix: A suffix used to generate the name of the referenced redacted attributes.
For example <tt>attr_accessor :data, prefix: '', suffix: '_cleaned'</tt>
would generate attributes named 'data_cleaned' to store the
cleaned up data.
Defaults to ''.
encryption_key: The encryption key to use for encrypted fields.
Defaults to nil. Required if you are using encryption.
digest_salt: The salt to use for digests
Defaults to “”
You can specify your own default options
class User
.merge!(redact: { :ssn => :remove })
attr_redactor :data
end
Example
class User
attr_redactor_options.merge!(encryption_key: 'some secret key')
attr_redactor :data, redact: {
:ssn => :remove, :email => :digest :medical_notes => :encrypt, }
end
@user = User.new
@user.redacted_data # nil
@user.data? # false
@user.data = { ssn: 'private', email: '[email protected]', medical_notes: 'private' }
@user.data? # true
@user.redacted_data # { email_digest: 'XXXXXX', encrypted_medical_notes: 'XXXXXX', encrypted_medical_notes_iv: 'XXXXXXX' }
@user.save!
@user = User.last
@user.data # { email_digest: 'XXXXXX', medical_notes: 'private' }
See README for more examples
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/attr_redactor.rb', line 87 def attr_redactor(*attributes) = attributes.last.is_a?(Hash) ? attributes.pop : {} = .dup.merge!().merge!() attributes.each do |attribute| redacted_attribute_name = ([:attribute] ? [:attribute] : [[:prefix], attribute, [:suffix]].join).to_sym instance_methods_as_symbols = attribute_instance_methods_as_symbols attr_reader redacted_attribute_name unless instance_methods_as_symbols.include?(redacted_attribute_name) attr_writer redacted_attribute_name unless instance_methods_as_symbols.include?(:"#{redacted_attribute_name}=") = .dup # Don't pass the filter mode in, in case it's dynamic .delete :filter_mode # Create a redactor for the attribute [:redactor] = HashRedactor::HashRedactor.new() define_method(attribute) do instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", unredact(attribute, send(redacted_attribute_name))) end define_method("#{attribute}=") do |value| send("#{redacted_attribute_name}=", redact(attribute, value)) instance_variable_set("@#{attribute}", value) # replace with redacted/unredacted value immediately instance_variable_set("@#{attribute}", unredact(attribute, send(redacted_attribute_name))) end define_method("#{attribute}?") do value = send(attribute) value.respond_to?(:empty?) ? !value.empty? : !!value end define_method("#{attribute}_redact_hash") do = redacted_attributes[attribute] [:redact] end redacted_attributes[attribute.to_sym] = .merge(attribute: redacted_attribute_name) end end |
#attr_redactor_options ⇒ Object
Default options to use with calls to attr_redactor
It will inherit existing options from its superclass
134 135 136 |
# File 'lib/attr_redactor.rb', line 134 def @attr_redactor_options ||= superclass..dup end |
#redact(attribute, value, options = {}) ⇒ Object
Redacts for the attribute specified
Example
class User
attr_redactor :data
end
redacted_data = User.redact(:data, { email: '[email protected]' })
196 197 198 199 200 201 202 203 |
# File 'lib/attr_redactor.rb', line 196 def redact(attribute, value, = {}) = redacted_attributes[attribute.to_sym].merge() if [:if] && ![:unless] && !value.nil? redacted_value = [:redactor].redact(value, ) else value end end |
#redacted_attributes ⇒ Object
Contains a hash of redacted attributes with virtual attribute names as keys and their corresponding options as values
Example
class User
attr_redactor :data, key: 'my secret key'
end
User.redacted_attributes # { data: { attribute: 'redacted_data', encryption_key: 'my secret key' } }
215 216 217 |
# File 'lib/attr_redactor.rb', line 215 def redacted_attributes @redacted_attributes ||= superclass.redacted_attributes.dup end |
#unredact(attribute, redacted_value, options = {}) ⇒ Object
Decrypts values in the attribute specified
Example
class User
attr_redactor :data
end
data = User.redact(:data, SOME_REDACTED_HASH)
177 178 179 180 181 182 183 184 185 |
# File 'lib/attr_redactor.rb', line 177 def unredact(attribute, redacted_value, = {}) = redacted_attributes[attribute.to_sym].merge() if [:if] && ![:unless] && !redacted_value.nil? value = [:redactor].decrypt(redacted_value, ) value else redacted_value end end |