shuber-attr_encrypted 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,14 @@
1
+ 2009-01-12 - Sean Huber (shuber@huberry.com)
2
+ * Remove read_attribute and write_attribute methods - unnecessary
3
+ * ActiveRecord and DataMapper extensions are now "adapters"
4
+ * Check for existing reader and writer methods separately before creating default ones for encrypted attributes
5
+
6
+ 2009-01-11 - Sean Huber (shuber@huberry.com)
7
+ * Update README
8
+
9
+ 2009-01-10 - Sean Huber (shuber@huberry.com)
10
+ * Update README
11
+
1
12
  2009-01-08 - Sean Huber (shuber@huberry.com)
2
13
  * Update comments and documentation
3
14
  * Update README
data/README.markdown CHANGED
@@ -3,7 +3,7 @@ attr\_encrypted
3
3
 
4
4
  Generates attr\_accessors that encrypt and decrypt attributes transparently
5
5
 
6
- Works with any class including ActiveRecord and DataMapper
6
+ Works with ANY class including ActiveRecord and DataMapper
7
7
 
8
8
 
9
9
  Installation
@@ -97,7 +97,7 @@ If your class has an instance method that determines the encryption key to use,
97
97
 
98
98
  #### Procs as keys ####
99
99
 
100
- You can pass a proc object as the `:key` option as well:
100
+ You can pass a proc/lambda object as the `:key` option as well:
101
101
 
102
102
  class User
103
103
  attr_encrypted :email, :key => proc { |user| ... }
@@ -109,12 +109,12 @@ You can pass a proc object as the `:key` option as well:
109
109
  There may be times that you want to only encrypt when certain conditions are met. For example maybe you're using rails and you don't want to encrypt
110
110
  attributes when you're in development mode. You can specify conditions like this:
111
111
 
112
- class User
112
+ class User < ActiveRecord::Base
113
113
  attr_encrypted :email, :key => 'a secret key', :unless => Rails.env.development?
114
114
  end
115
115
 
116
116
  You can specify both `:if` and `:unless` options. If you pass a symbol representing an instance method then the result of the method will be evaluated.
117
- Any objects that respond to :call are evaluated as well.
117
+ Any objects that respond to `:call` are evaluated as well.
118
118
 
119
119
 
120
120
  ### Custom encryptor ###
@@ -2,14 +2,6 @@ require 'huberry/attr_encrypted/class'
2
2
  Class.send :include, Huberry::AttrEncrypted::Class
3
3
 
4
4
  require 'huberry/attr_encrypted/object'
5
- Object.send :include, Huberry::AttrEncrypted::Object
5
+ Object.extend Huberry::AttrEncrypted::Object
6
6
 
7
- if defined?(ActiveRecord)
8
- require 'huberry/attr_encrypted/active_record'
9
- ActiveRecord::Base.extend Huberry::AttrEncrypted::ActiveRecord
10
- end
11
-
12
- if defined?(DataMapper)
13
- require 'huberry/attr_encrypted/data_mapper'
14
- DataMapper::Resource.send :include, Huberry::AttrEncrypted::DataMapper
15
- end
7
+ Dir[File.join(File.dirname(__FILE__), 'huberry', 'attr_encrypted', 'adapters', '*.rb')].each { |file| require file }
@@ -0,0 +1,58 @@
1
+ if defined?(ActiveRecord)
2
+ module Huberry
3
+ module AttrEncrypted
4
+ module Adapters
5
+ module ActiveRecord
6
+ def self.extended(base)
7
+ base.eigenclass_eval { alias_method_chain :method_missing, :attr_encrypted }
8
+ end
9
+
10
+ protected
11
+
12
+ # Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
13
+ # unless they've already been specified
14
+ #
15
+ # Also defines the attribute methods for db fields if they don't exist yet
16
+ def attr_encrypted(*attrs)
17
+ define_attribute_methods
18
+ options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
19
+ super *(attrs << options)
20
+ end
21
+
22
+ # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
23
+ # encrypted attributes
24
+ #
25
+ # NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
26
+ #
27
+ # This is useful for encrypting fields like email addresses. Your user's email addresses
28
+ # are encrypted in the database, but you can still look up a user by email for logging in
29
+ #
30
+ # Example
31
+ #
32
+ # class User < ActiveRecord::Base
33
+ # attr_encrypted :email, :key => 'secret key'
34
+ # end
35
+ #
36
+ # User.find_by_email_and_password('test@example.com', 'testing')
37
+ # # results in a call to
38
+ # User.find_by_encrypted_email_and_password('the_encrypted_version_of_test@example.com', 'testing')
39
+ def method_missing_with_attr_encrypted(method, *args, &block)
40
+ if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
41
+ attribute_names = match.captures.last.split('_and_')
42
+ attribute_names.each_with_index do |attribute, index|
43
+ if attr_encrypted?(attribute)
44
+ args[index] = send("encrypt_#{attribute}", args[index])
45
+ attribute_names[index] = encrypted_attributes[attribute]
46
+ end
47
+ end
48
+ method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
49
+ end
50
+ method_missing_without_attr_encrypted(method, *args, &block)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ ActiveRecord::Base.extend Huberry::AttrEncrypted::Adapters::ActiveRecord
58
+ end
@@ -0,0 +1,25 @@
1
+ if defined?(DataMapper)
2
+ module Huberry
3
+ module AttrEncrypted
4
+ module Adapters
5
+ module DataMapper
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ protected
12
+ # Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
13
+ # unless they've already been specified
14
+ def attr_encrypted(*attrs)
15
+ options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
16
+ super *(attrs << options)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ DataMapper::Resource.send :include, Huberry::AttrEncrypted::Adapters::DataMapper
25
+ end
@@ -89,14 +89,15 @@ module Huberry
89
89
  :unless => false
90
90
  }.merge(attr_encrypted_options).merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
91
91
  options[:encode] = 'm*' if options[:encode] == true
92
-
92
+
93
93
  attrs.each do |attribute|
94
94
  encrypted_attribute_name = options[:attribute].nil? ? options[:prefix].to_s + attribute.to_s + options[:suffix].to_s : options[:attribute].to_s
95
-
95
+
96
96
  encrypted_attributes[attribute.to_s] = encrypted_attribute_name
97
-
98
- attr_accessor encrypted_attribute_name.to_sym unless instance_methods.include?(encrypted_attribute_name)
99
-
97
+
98
+ attr_reader encrypted_attribute_name.to_sym unless instance_methods.include?(encrypted_attribute_name)
99
+ attr_writer encrypted_attribute_name.to_sym unless instance_methods.include?("#{encrypted_attribute_name}=")
100
+
100
101
  define_class_method "encrypt_#{attribute}" do |value|
101
102
  if options[:if] && !options[:unless]
102
103
  if value.nil?
@@ -111,7 +112,7 @@ module Huberry
111
112
  value
112
113
  end
113
114
  end
114
-
115
+
115
116
  define_class_method "decrypt_#{attribute}" do |encrypted_value|
116
117
  if options[:if] && !options[:unless]
117
118
  if encrypted_value.nil?
@@ -126,10 +127,10 @@ module Huberry
126
127
  encrypted_value
127
128
  end
128
129
  end
129
-
130
+
130
131
  define_method "#{attribute}" do
131
132
  value = instance_variable_get("@#{attribute}")
132
- encrypted_value = read_attribute(encrypted_attribute_name)
133
+ encrypted_value = send(encrypted_attribute_name.to_s)
133
134
  original_options = [:key, :if, :unless].inject({}) do |hash, option|
134
135
  hash[option] = options[option]
135
136
  options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
@@ -139,20 +140,20 @@ module Huberry
139
140
  options.merge!(original_options)
140
141
  value
141
142
  end
142
-
143
+
143
144
  define_method "#{attribute}=" do |value|
144
145
  original_options = [:key, :if, :unless].inject({}) do |hash, option|
145
146
  hash[option] = options[option]
146
147
  options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
147
148
  hash
148
149
  end
149
- write_attribute(encrypted_attribute_name, self.class.send("encrypt_#{attribute}".to_sym, value))
150
+ send("#{encrypted_attribute_name}=".to_sym, self.class.send("encrypt_#{attribute}".to_sym, value))
150
151
  options.merge!(original_options)
151
152
  instance_variable_set("@#{attribute}", value)
152
153
  end
153
154
  end
154
155
  end
155
-
156
+
156
157
  # Evaluates an option specified as a symbol representing an instance method or a proc
157
158
  # If the option is not a symbol or proc then the original option is returned
158
159
  def evaluate_attr_encrypted_option(option, object)
@@ -1,46 +1,50 @@
1
1
  module Huberry
2
2
  module AttrEncrypted
3
3
  module Object
4
- def self.included(base)
5
- base.class_eval do
6
- extend ClassMethods
7
- eattr_accessor :attr_encrypted_options, :encrypted_attributes
8
- attr_encrypted_options = {}
9
- encrypted_attributes = {}
10
- end
4
+ def self.extended(base)
5
+ base.attr_encrypted_options = {}
6
+ base.instance_variable_set('@encrypted_attributes', {})
11
7
  end
12
-
13
- # Wraps instance_variable_get
14
- def read_attribute(attribute)
15
- instance_variable_get("@#{attribute}")
8
+
9
+ # Default options to use with calls to <tt>attr_encrypted</tt>.
10
+ #
11
+ # It will inherit existing options from its parent class
12
+ def attr_encrypted_options
13
+ @attr_encrypted_options ||= superclass.attr_encrypted_options.nil? ? {} : superclass.attr_encrypted_options.dup
14
+ end
15
+
16
+ # Sets default options to use with calls to <tt>attr_encrypted</tt>.
17
+ def attr_encrypted_options=(options)
18
+ @attr_encrypted_options = options
16
19
  end
17
-
18
- # Wraps instance_variable_set
19
- def write_attribute(attribute, value)
20
- instance_variable_set("@#{attribute}", value)
20
+
21
+ # Contains a hash of encrypted attributes with virtual attribute names as keys and real attribute
22
+ # names as values
23
+ #
24
+ # Example
25
+ #
26
+ # class User
27
+ # attr_encrypted :email
28
+ # end
29
+ #
30
+ # User.encrypted_attributes # { 'email' => 'encrypted_email' }
31
+ def encrypted_attributes
32
+ @encrypted_attributes ||= superclass.encrypted_attributes.nil? ? {} : superclass.encrypted_attributes.dup
21
33
  end
22
-
23
- module ClassMethods
24
- # Checks if an attribute has been configured to be encrypted
25
- #
26
- # Example
27
- #
28
- # class User
29
- # attr_accessor :name
30
- # attr_encrypted :email
31
- # end
32
- #
33
- # User.attr_encrypted?(:name) # false
34
- # User.attr_encrypted?(:email) # true
35
- def attr_encrypted?(attribute)
36
- encrypted_attributes.keys.include?(attribute.to_s)
37
- end
38
34
 
39
- # Copies existing encrypted attributes and options to the derived class
40
- def inherited(base)
41
- base.attr_encrypted_options = self.attr_encrypted_options.nil? ? {} : self.attr_encrypted_options.dup
42
- base.encrypted_attributes = self.encrypted_attributes.nil? ? {} : self.encrypted_attributes.dup
43
- end
35
+ # Checks if an attribute has been configured to be encrypted
36
+ #
37
+ # Example
38
+ #
39
+ # class User
40
+ # attr_accessor :name
41
+ # attr_encrypted :email
42
+ # end
43
+ #
44
+ # User.attr_encrypted?(:name) # false
45
+ # User.attr_encrypted?(:email) # true
46
+ def attr_encrypted?(attribute)
47
+ encrypted_attributes.keys.include?(attribute.to_s)
44
48
  end
45
49
  end
46
50
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shuber-attr_encrypted
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Huber
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-08 00:00:00 -08:00
12
+ date: 2009-01-12 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -41,9 +41,9 @@ extra_rdoc_files: []
41
41
  files:
42
42
  - CHANGELOG
43
43
  - lib/attr_encrypted.rb
44
- - lib/huberry/attr_encrypted/active_record.rb
44
+ - lib/huberry/attr_encrypted/adapters/active_record.rb
45
+ - lib/huberry/attr_encrypted/adapters/data_mapper.rb
45
46
  - lib/huberry/attr_encrypted/class.rb
46
- - lib/huberry/attr_encrypted/data_mapper.rb
47
47
  - lib/huberry/attr_encrypted/object.rb
48
48
  - MIT-LICENSE
49
49
  - Rakefile
@@ -1,50 +0,0 @@
1
- module Huberry
2
- module AttrEncrypted
3
- module ActiveRecord
4
- def self.extended(base)
5
- base.eigenclass_eval { alias_method_chain :method_missing, :attr_encrypted }
6
- end
7
-
8
- protected
9
-
10
- # Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
11
- # unless they've already been specified
12
- def attr_encrypted(*attrs)
13
- define_attribute_methods
14
- options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
15
- super *(attrs << options)
16
- end
17
-
18
- # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
19
- # encrypted attributes
20
- #
21
- # NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
22
- #
23
- # This is useful for encrypting fields like email addresses. Your user's email addresses
24
- # are encrypted in the database, but you can still look up a user by email for logging in
25
- #
26
- # Example
27
- #
28
- # class User < ActiveRecord::Base
29
- # attr_encrypted :email, :key => 'secret key'
30
- # end
31
- #
32
- # User.find_by_email_and_password('test@example.com', 'testing')
33
- # # results in a call to
34
- # User.find_by_encrypted_email_and_password('the_encrypted_version_of_test@example.com', 'testing')
35
- def method_missing_with_attr_encrypted(method, *args, &block)
36
- if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
37
- attribute_names = match.captures.last.split('_and_')
38
- attribute_names.each_with_index do |attribute, index|
39
- if attr_encrypted?(attribute)
40
- args[index] = send("encrypt_#{attribute}", args[index])
41
- attribute_names[index] = encrypted_attributes[attribute]
42
- end
43
- end
44
- method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
45
- end
46
- method_missing_without_attr_encrypted(method, *args, &block)
47
- end
48
- end
49
- end
50
- end
@@ -1,23 +0,0 @@
1
- module Huberry
2
- module AttrEncrypted
3
- module DataMapper
4
- def self.included(base)
5
- base.class_eval do
6
- extend ClassMethods
7
- alias_method :read_attribute, :attribute_get
8
- alias_method :write_attribute, :attribute_set
9
- end
10
- end
11
-
12
- module ClassMethods
13
- protected
14
- # Calls attr_encrypted with the options <tt>:encode</tt> and <tt>:marshal</tt> set to true
15
- # unless they've already been specified
16
- def attr_encrypted(*attrs)
17
- options = { :encode => true, :marshal => true }.merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
18
- super *(attrs << options)
19
- end
20
- end
21
- end
22
- end
23
- end