Module: YattrEncrypted
- Defined in:
- lib/yattr_encrypted.rb,
lib/yattr_encrypted/railtie.rb,
lib/yattr_encrypted/version.rb
Overview
Adds attr_accessors that encrypt and decrypt an object’s attributes
Defined Under Namespace
Classes: Railtie
Constant Summary collapse
- ALGORITHM =
'aes-256-cbc'- VERSION =
'0.1.7'
Class Method Summary collapse
-
.included(base) ⇒ Object
Generates attr_accessors that encrypt and decrypt attributes transparently.
Class Method Details
.included(base) ⇒ Object
Generates attr_accessors that encrypt and decrypt attributes transparently
Options (any other options you specify are passed to the encryptor’s encrypt and decrypt methods)
:prefix A prefix used to generate the name of the referenced
encrypted attributes. For example <tt>attr_accessor
:email, :password, :prefix => 'crypted_'</tt> would
generate attributes named 'crypted_email' and
'crypted_password' to store the encrypted email and
password. Defaults to ''.
:suffix A suffix used to generate the name of the referenced
encrypted attributes. For example <tt>attr_accessor
:email, :password, :prefix => '', :suffix =>
'_encrypted'</tt> would generate attributes named
'email_encrypted' and 'password_encrypted' to store the
encrypted email. Defaults to '_encrypted'.
:key The encryption key. Not generally required.
Defaults to Rails.application.config.secret_token
Example
class User
yattr_encrypted :email
end
@user = User.new
@user.encrypted_email # nil? is true
@user.email? # false
@user.email = '[email protected]'
@user.email? # true
@user.encrypted_email # returns the encrypted version of '[email protected]'
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/yattr_encrypted.rb', line 54 def self.included(base) class << base attr_accessor :yate_encrypted_attributes def yattr_encrypted(*attributes) # construct options = { :prefix => '', :suffix => '_encrypted', :key => defined?(::Rails) ? ::Rails.application.config.secret_token : nil, } # merge specific options .merge!(attributes.pop) if Hash === attributes.last # tell self to define instance methods from the database if they have not already been generated define_attribute_methods unless attribute_methods_generated? # schedule yattr_update_encrypted_values before save self.send :before_save, :yate_update_encrypted_values unless self.yate_encrypted_attributes # collect existing instance methods instance_methods_as_symbols = instance_methods.map { |method| method.to_sym } # iterate through attributes and create accessors, verify encryped accessors exist attributes.map { |x| x.to_sym }.each do |attribute| encrypted_attribute_name = [[:prefix], attribute, [:suffix]].join.to_sym # barf if reader and write doesn't exist for encrypted attribute raise ArgumentError.new("No Reader method for encrypted version of #{attribute}: #{encrypted_attribute_name}") \ unless instance_methods_as_symbols.include?(encrypted_attribute_name) raise ArgumentError.new("No Write method for encrypted version of #{attribute}: #{encrypted_attribute_name}") \ unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=") tmp =<<-XXX def #{attribute} options = yate_encrypted_attributes[:#{attribute}] if @#{attribute}.nil? || @#{attribute}.empty? @#{attribute} = #{encrypted_attribute_name} ? \ yate_decrypt(#{encrypted_attribute_name}, options[:key]) : \ '' if options[:read_filter].respond_to? :call @#{attribute} = options[:read_filter].call(@#{attribute}) elsif options[:read_filter] @#{attribute} = self.send options[:read_filter].to_sym, @#{attribute} end self.yate_checksums[:#{attribute}] = yate_attribute_hash_value(:#{attribute}) self.yate_dirty[:#{attribute}] = true elsif options[:read_filter] if options[:read_filter].respond_to? :call @#{attribute} = options[:read_filter].call(@#{attribute}) else @#{attribute} = self.send options[:read_filter].to_sym, @#{attribute} end end @#{attribute} end XXX class_eval(tmp) tmp =<<-XXX def #{attribute}= value options = yate_encrypted_attributes[:#{attribute}] if options[:write_filter].respond_to? :call value = options[:write_filter].call(value) elsif options[:write_filter] value = self.send options[:write_filter], value end @#{attribute} = value self.#{encrypted_attribute_name} = yate_encrypt(value, options[:key]) self.yate_checksums[:#{attribute}] = yate_attribute_hash_value(:#{attribute}) self.yate_dirty[:#{attribute}] = true end XXX class_eval(tmp) define_method("#{attribute}?") do value = send(attribute) value.respond_to?(:empty?) ? !value.empty? : !!value end self.yate_encrypted_attributes ||= {} self.yate_encrypted_attributes[attribute.to_sym] = \ .merge(:attribute => encrypted_attribute_name) # this conditioning is a hack to allow stand alone tests to work # one of these days 'real soon now' I'll figure out how to # stub out Rails::Railtie, but until then. . . if defined?(Rails) # add to filter_parameters keep out of log Rails.application.config.filter_parameters += [attribute, encrypted_attribute_name] # protect encrypted field from mass assignment attr_protected encrypted_attribute_name.to_sym end end end end end |