attr_encrypted 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,13 +2,15 @@ if defined?(ActiveRecord)
2
2
  module AttrEncrypted
3
3
  module Adapters
4
4
  module ActiveRecord
5
- def self.extended(base)
6
- base.attr_encrypted_options[:encode] = true
7
- base.eigenclass_eval { alias_method_chain :method_missing, :attr_encrypted }
5
+ def self.extended(base) # :nodoc:
6
+ base.class_eval do
7
+ attr_encrypted_options[:encode] = true
8
+ class << self; alias_method_chain :method_missing, :attr_encrypted; end
9
+ end
8
10
  end
9
-
11
+
10
12
  protected
11
-
13
+
12
14
  # Ensures the attribute methods for db fields have been defined before calling the original
13
15
  # <tt>attr_encrypted</tt> method
14
16
  def attr_encrypted(*attrs)
@@ -16,7 +18,7 @@ if defined?(ActiveRecord)
16
18
  super
17
19
  attrs.reject { |attr| attr.is_a?(Hash) }.each { |attr| alias_method "#{attr}_before_type_cast", attr }
18
20
  end
19
-
21
+
20
22
  # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
21
23
  # encrypted attributes
22
24
  #
@@ -40,7 +42,7 @@ if defined?(ActiveRecord)
40
42
  attribute_names.each_with_index do |attribute, index|
41
43
  if attr_encrypted?(attribute)
42
44
  args[index] = send("encrypt_#{attribute}", args[index])
43
- attribute_names[index] = encrypted_attributes[attribute]
45
+ attribute_names[index] = encrypted_attributes[attribute.to_sym][:attribute]
44
46
  end
45
47
  end
46
48
  method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
@@ -50,6 +52,6 @@ if defined?(ActiveRecord)
50
52
  end
51
53
  end
52
54
  end
53
-
55
+
54
56
  ActiveRecord::Base.extend AttrEncrypted::Adapters::ActiveRecord
55
57
  end
@@ -2,13 +2,13 @@ if defined?(DataMapper)
2
2
  module AttrEncrypted
3
3
  module Adapters
4
4
  module DataMapper
5
- def self.extended(base)
6
- base.eigenclass_eval do
5
+ def self.extended(base) # :nodoc:
6
+ class << base
7
7
  alias_method :included_without_attr_encrypted, :included
8
8
  alias_method :included, :included_with_attr_encrypted
9
9
  end
10
10
  end
11
-
11
+
12
12
  def included_with_attr_encrypted(base)
13
13
  included_without_attr_encrypted(base)
14
14
  base.attr_encrypted_options[:encode] = true
@@ -16,6 +16,6 @@ if defined?(DataMapper)
16
16
  end
17
17
  end
18
18
  end
19
-
19
+
20
20
  DataMapper::Resource.extend AttrEncrypted::Adapters::DataMapper
21
21
  end
@@ -2,12 +2,12 @@ if defined?(Sequel)
2
2
  module AttrEncrypted
3
3
  module Adapters
4
4
  module Sequel
5
- def self.extended(base)
5
+ def self.extended(base) # :nodoc:
6
6
  base.attr_encrypted_options[:encode] = true
7
7
  end
8
8
  end
9
9
  end
10
10
  end
11
-
11
+
12
12
  Sequel::Model.extend AttrEncrypted::Adapters::Sequel
13
13
  end
@@ -0,0 +1,17 @@
1
+ module AttrEncrypted
2
+ # Contains information about this gem's version
3
+ module Version
4
+ MAJOR = 1
5
+ MINOR = 2
6
+ PATCH = 0
7
+
8
+ # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
9
+ #
10
+ # Example
11
+ #
12
+ # Version.string # '1.0.2'
13
+ def self.string
14
+ [MAJOR, MINOR, PATCH].join('.')
15
+ end
16
+ end
17
+ end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/test_helper'
1
+ require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
4
4
 
@@ -18,15 +18,25 @@ end
18
18
  # The table needs to exist before defining the class
19
19
  create_people_table
20
20
 
21
+ ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
22
+
21
23
  class Person < ActiveRecord::Base
22
24
  attr_encrypted :email, :key => 'a secret key'
23
25
  attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'some private key') }, :marshal => true
24
-
25
- def after_initialize
26
- self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
27
- self.credentials ||= { :username => 'example', :password => 'test' }
28
- rescue ActiveRecord::MissingAttributeError
29
- end
26
+
27
+ ActiveSupport::Deprecation.silenced = true
28
+ def after_initialize; end
29
+ ActiveSupport::Deprecation.silenced = false
30
+
31
+ after_initialize :initialize_salt_and_credentials
32
+
33
+ protected
34
+
35
+ def initialize_salt_and_credentials
36
+ self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
37
+ self.credentials ||= { :username => 'example', :password => 'test' }
38
+ rescue ActiveRecord::MissingAttributeError
39
+ end
30
40
  end
31
41
 
32
42
  class PersonWithValidation < Person
@@ -35,64 +45,64 @@ class PersonWithValidation < Person
35
45
  end
36
46
 
37
47
  class ActiveRecordTest < Test::Unit::TestCase
38
-
48
+
39
49
  def setup
40
50
  ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
41
51
  create_people_table
42
52
  end
43
-
53
+
44
54
  def test_should_encrypt_email
45
55
  @person = Person.create :email => 'test@example.com'
46
56
  assert_not_nil @person.encrypted_email
47
57
  assert_not_equal @person.email, @person.encrypted_email
48
58
  assert_equal @person.email, Person.find(:first).email
49
59
  end
50
-
60
+
51
61
  def test_should_marshal_and_encrypt_credentials
52
62
  @person = Person.create
53
63
  assert_not_nil @person.encrypted_credentials
54
64
  assert_not_equal @person.credentials, @person.encrypted_credentials
55
65
  assert_equal @person.credentials, Person.find(:first).credentials
56
66
  end
57
-
67
+
58
68
  def test_should_find_by_email
59
69
  @person = Person.create(:email => 'test@example.com')
60
70
  assert_equal @person, Person.find_by_email('test@example.com')
61
71
  end
62
-
72
+
63
73
  def test_should_find_by_email_and_password
64
74
  Person.create(:email => 'test@example.com', :password => 'invalid')
65
75
  @person = Person.create(:email => 'test@example.com', :password => 'test')
66
76
  assert_equal @person, Person.find_by_email_and_password('test@example.com', 'test')
67
77
  end
68
-
78
+
69
79
  def test_should_scope_by_email
70
80
  @person = Person.create(:email => 'test@example.com')
71
81
  assert_equal @person, Person.scoped_by_email('test@example.com').find(:first) rescue NoMethodError
72
82
  end
73
-
83
+
74
84
  def test_should_scope_by_email_and_password
75
85
  Person.create(:email => 'test@example.com', :password => 'invalid')
76
86
  @person = Person.create(:email => 'test@example.com', :password => 'test')
77
87
  assert_equal @person, Person.scoped_by_email_and_password('test@example.com', 'test').find(:first) rescue NoMethodError
78
88
  end
79
-
89
+
80
90
  def test_should_encode_by_default
81
91
  assert Person.attr_encrypted_options[:encode]
82
92
  end
83
-
93
+
84
94
  def test_should_validate_presence_of_email
85
95
  @person = PersonWithValidation.new
86
96
  assert !@person.valid?
87
- assert @person.errors.on(:email)
97
+ assert !@person.errors[:email].empty? || @person.errors.on(:email)
88
98
  end
89
-
99
+
90
100
  def test_should_validate_uniqueness_of_email
91
101
  @person = PersonWithValidation.new :email => 'test@example.com'
92
102
  assert @person.save
93
103
  @person2 = PersonWithValidation.new :email => @person.email
94
104
  assert !@person2.valid?
95
- assert @person2.errors.on(:encrypted_email)
105
+ assert !@person2.errors[:encrypted_email].empty? || @person2.errors.on(:encrypted_email)
96
106
  end
97
-
107
+
98
108
  end
@@ -1,11 +1,10 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
- require 'mocha'
1
+ require File.expand_path('../test_helper', __FILE__)
3
2
 
4
3
  class SillyEncryptor
5
4
  def self.silly_encrypt(options)
6
5
  (options[:value] + options[:some_arg]).reverse
7
6
  end
8
-
7
+
9
8
  def self.silly_decrypt(options)
10
9
  options[:value].reverse.gsub(/#{options[:some_arg]}$/, '')
11
10
  end
@@ -13,7 +12,7 @@ end
13
12
 
14
13
  class User
15
14
  self.attr_encrypted_options[:key] = Proc.new { |user| user.class.to_s } # default key
16
-
15
+
17
16
  attr_encrypted :email, :without_encoding, :key => 'secret key'
18
17
  attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
19
18
  attr_encrypted :ssn, :key => :salt, :attribute => 'ssn_encrypted'
@@ -26,12 +25,12 @@ class User
26
25
  attr_encrypted :with_true_unless, :key => 'secret key', :unless => true
27
26
  attr_encrypted :with_false_unless, :key => 'secret key', :unless => false
28
27
  attr_encrypted :with_if_changed, :key => 'secret key', :if => :should_encrypt
29
-
28
+
30
29
  attr_encryptor :aliased, :key => 'secret_key'
31
-
30
+
32
31
  attr_accessor :salt
33
32
  attr_accessor :should_encrypt
34
-
33
+
35
34
  def initialize
36
35
  self.salt = Time.now.to_i.to_s
37
36
  self.should_encrypt = true
@@ -49,48 +48,48 @@ class SomeOtherClass
49
48
  end
50
49
 
51
50
  class AttrEncryptedTest < Test::Unit::TestCase
52
-
51
+
53
52
  def test_should_store_email_in_encrypted_attributes
54
- assert User.encrypted_attributes.include?('email')
53
+ assert User.encrypted_attributes.include?(:email)
55
54
  end
56
-
55
+
57
56
  def test_should_not_store_salt_in_encrypted_attributes
58
- assert !User.encrypted_attributes.include?('salt')
57
+ assert !User.encrypted_attributes.include?(:salt)
59
58
  end
60
-
59
+
61
60
  def test_attr_encrypted_should_return_true_for_email
62
61
  assert User.attr_encrypted?('email')
63
62
  end
64
-
63
+
65
64
  def test_attr_encrypted_should_return_false_for_salt
66
65
  assert !User.attr_encrypted?('salt')
67
66
  end
68
-
67
+
69
68
  def test_should_generate_an_encrypted_attribute
70
69
  assert User.new.respond_to?(:encrypted_email)
71
70
  end
72
-
71
+
73
72
  def test_should_generate_an_encrypted_attribute_with_a_prefix_and_suffix
74
73
  assert User.new.respond_to?(:crypted_password_test)
75
74
  end
76
-
75
+
77
76
  def test_should_generate_an_encrypted_attribute_with_the_attribute_option
78
77
  assert User.new.respond_to?(:ssn_encrypted)
79
78
  end
80
-
79
+
81
80
  def test_should_not_encrypt_nil_value
82
81
  assert_nil User.encrypt_email(nil)
83
82
  end
84
-
83
+
85
84
  def test_should_not_encrypt_empty_string
86
85
  assert_equal '', User.encrypt_email('')
87
86
  end
88
-
87
+
89
88
  def test_should_encrypt_email
90
89
  assert_not_nil User.encrypt_email('test@example.com')
91
90
  assert_not_equal 'test@example.com', User.encrypt_email('test@example.com')
92
91
  end
93
-
92
+
94
93
  def test_should_encrypt_email_when_modifying_the_attr_writer
95
94
  @user = User.new
96
95
  assert_nil @user.encrypted_email
@@ -98,55 +97,55 @@ class AttrEncryptedTest < Test::Unit::TestCase
98
97
  assert_not_nil @user.encrypted_email
99
98
  assert_equal User.encrypt_email('test@example.com'), @user.encrypted_email
100
99
  end
101
-
100
+
102
101
  def test_should_not_decrypt_nil_value
103
102
  assert_nil User.decrypt_email(nil)
104
103
  end
105
-
104
+
106
105
  def test_should_not_decrypt_empty_string
107
106
  assert_equal '', User.decrypt_email('')
108
107
  end
109
-
108
+
110
109
  def test_should_decrypt_email
111
110
  encrypted_email = User.encrypt_email('test@example.com')
112
111
  assert_not_equal 'test@test.com', encrypted_email
113
112
  assert_equal 'test@example.com', User.decrypt_email(encrypted_email)
114
113
  end
115
-
114
+
116
115
  def test_should_decrypt_email_when_reading
117
116
  @user = User.new
118
117
  assert_nil @user.email
119
118
  @user.encrypted_email = User.encrypt_email('test@example.com')
120
119
  assert_equal 'test@example.com', @user.email
121
120
  end
122
-
121
+
123
122
  def test_should_encrypt_with_encoding
124
- assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m*')
123
+ assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
125
124
  end
126
-
125
+
127
126
  def test_should_decrypt_with_encoding
128
127
  encrypted = User.encrypt_with_encoding('test')
129
128
  assert_equal 'test', User.decrypt_with_encoding(encrypted)
130
- assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m*').to_s)
129
+ assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
131
130
  end
132
-
131
+
133
132
  def test_should_encrypt_with_custom_encoding
134
133
  assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
135
134
  end
136
-
135
+
137
136
  def test_should_decrypt_with_custom_encoding
138
137
  encrypted = User.encrypt_with_encoding('test')
139
138
  assert_equal 'test', User.decrypt_with_encoding(encrypted)
140
- assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').to_s)
139
+ assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
141
140
  end
142
-
141
+
143
142
  def test_should_encrypt_with_marshaling
144
143
  @user = User.new
145
144
  @user.with_marshaling = [1, 2, 3]
146
145
  assert_not_nil @user.encrypted_with_marshaling
147
146
  assert_equal User.encrypt_with_marshaling([1, 2, 3]), @user.encrypted_with_marshaling
148
147
  end
149
-
148
+
150
149
  def test_should_decrypt_with_marshaling
151
150
  encrypted = User.encrypt_with_marshaling([1, 2, 3])
152
151
  @user = User.new
@@ -154,11 +153,11 @@ class AttrEncryptedTest < Test::Unit::TestCase
154
153
  @user.encrypted_with_marshaling = encrypted
155
154
  assert_equal [1, 2, 3], @user.with_marshaling
156
155
  end
157
-
156
+
158
157
  def test_should_use_custom_encryptor_and_crypt_method_names_and_arguments
159
158
  assert_equal SillyEncryptor.silly_encrypt(:value => 'testing', :some_arg => 'test'), User.encrypt_credit_card('testing')
160
159
  end
161
-
160
+
162
161
  def test_should_evaluate_a_key_passed_as_a_symbol
163
162
  @user = User.new
164
163
  assert_nil @user.ssn_encrypted
@@ -166,7 +165,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
166
165
  assert_not_nil @user.ssn_encrypted
167
166
  assert_equal Encryptor.encrypt(:value => 'testing', :key => @user.salt), @user.ssn_encrypted
168
167
  end
169
-
168
+
170
169
  def test_should_evaluate_a_key_passed_as_a_proc
171
170
  @user = User.new
172
171
  assert_nil @user.crypted_password_test
@@ -174,7 +173,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
174
173
  assert_not_nil @user.crypted_password_test
175
174
  assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
176
175
  end
177
-
176
+
178
177
  def test_should_use_options_found_in_the_attr_encrypted_options_attribute
179
178
  @user = User.new
180
179
  assert_nil @user.crypted_password_test
@@ -182,41 +181,41 @@ class AttrEncryptedTest < Test::Unit::TestCase
182
181
  assert_not_nil @user.crypted_password_test
183
182
  assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
184
183
  end
185
-
184
+
186
185
  def test_should_inherit_encrypted_attributes
187
- assert_equal User.encrypted_attributes.merge('testing' => 'encrypted_testing'), Admin.encrypted_attributes
186
+ assert_equal [User.encrypted_attributes.keys, :testing].flatten.collect { |key| key.to_s }.sort, Admin.encrypted_attributes.keys.collect { |key| key.to_s }.sort
188
187
  end
189
-
188
+
190
189
  def test_should_inherit_attr_encrypted_options
191
190
  assert !User.attr_encrypted_options.empty?
192
191
  assert_equal User.attr_encrypted_options, Admin.attr_encrypted_options
193
192
  end
194
-
193
+
195
194
  def test_should_not_inherit_unrelated_attributes
196
195
  assert SomeOtherClass.attr_encrypted_options.empty?
197
196
  assert SomeOtherClass.encrypted_attributes.empty?
198
197
  end
199
-
198
+
200
199
  def test_should_evaluate_a_symbol_option
201
- assert_equal Object, Object.send(:evaluate_attr_encrypted_option, :class, Object.new)
200
+ assert_equal Object, Object.new.send(:evaluate_attr_encrypted_option, :class)
202
201
  end
203
-
202
+
204
203
  def test_should_evaluate_a_proc_option
205
- assert_equal Object, Object.send(:evaluate_attr_encrypted_option, proc { |object| object.class }, Object.new)
204
+ assert_equal Object, Object.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
206
205
  end
207
-
206
+
208
207
  def test_should_evaluate_a_lambda_option
209
- assert_equal Object, Object.send(:evaluate_attr_encrypted_option, lambda { |object| object.class }, Object.new)
208
+ assert_equal Object, Object.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
210
209
  end
211
-
210
+
212
211
  def test_should_evaluate_a_method_option
213
- assert_equal Object, Object.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call), Object.new)
212
+ assert_equal Object, Object.new.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call))
214
213
  end
215
-
214
+
216
215
  def test_should_return_a_string_option
217
- assert_equal 'Object', Object.send(:evaluate_attr_encrypted_option, 'Object', Object.new)
216
+ assert_equal 'Object', Object.new.send(:evaluate_attr_encrypted_option, 'Object')
218
217
  end
219
-
218
+
220
219
  def test_should_encrypt_with_true_if
221
220
  @user = User.new
222
221
  assert_nil @user.encrypted_with_true_if
@@ -224,7 +223,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
224
223
  assert_not_nil @user.encrypted_with_true_if
225
224
  assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_true_if
226
225
  end
227
-
226
+
228
227
  def test_should_not_encrypt_with_false_if
229
228
  @user = User.new
230
229
  assert_nil @user.encrypted_with_false_if
@@ -232,7 +231,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
232
231
  assert_not_nil @user.encrypted_with_false_if
233
232
  assert_equal 'testing', @user.encrypted_with_false_if
234
233
  end
235
-
234
+
236
235
  def test_should_encrypt_with_false_unless
237
236
  @user = User.new
238
237
  assert_nil @user.encrypted_with_false_unless
@@ -240,7 +239,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
240
239
  assert_not_nil @user.encrypted_with_false_unless
241
240
  assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_false_unless
242
241
  end
243
-
242
+
244
243
  def test_should_not_encrypt_with_true_unless
245
244
  @user = User.new
246
245
  assert_nil @user.encrypted_with_true_unless
@@ -248,11 +247,11 @@ class AttrEncryptedTest < Test::Unit::TestCase
248
247
  assert_not_nil @user.encrypted_with_true_unless
249
248
  assert_equal 'testing', @user.encrypted_with_true_unless
250
249
  end
251
-
250
+
252
251
  def test_should_work_with_aliased_attr_encryptor
253
- assert User.encrypted_attributes.include?('aliased')
252
+ assert User.encrypted_attributes.include?(:aliased)
254
253
  end
255
-
254
+
256
255
  def test_should_always_reset_options
257
256
  @user = User.new
258
257
  @user.with_if_changed = "encrypt_stuff"
@@ -261,12 +260,12 @@ class AttrEncryptedTest < Test::Unit::TestCase
261
260
  assert_raise RuntimeError do
262
261
  @user.with_if_changed
263
262
  end
264
-
263
+
265
264
  @user = User.new
266
265
  @user.should_encrypt = false
267
266
  @user.with_if_changed = "not_encrypted_stuff"
268
267
  assert_equal "not_encrypted_stuff", @user.with_if_changed
269
268
  assert_equal "not_encrypted_stuff", @user.encrypted_with_if_changed
270
269
  end
271
-
270
+
272
271
  end