attr_encrypted 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = attr_encrypted
1
+ = attr_encrypted {<img src="https://travis-ci.org/attr-encrypted/attr_encrypted.png" />}[https://travis-ci.org/attr-encrypted/attr_encrypted]
2
2
 
3
3
  Generates attr_accessors that encrypt and decrypt attributes transparently
4
4
 
@@ -299,4 +299,4 @@ Just like the default options for <tt>ActiveRecord</tt>, the <tt>:encode</tt> op
299
299
  * Add tests for it. This is important so I don't break it in a
300
300
  future version unintentionally.
301
301
  * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
302
- * Send me a pull request. Bonus points for topic branches.
302
+ * Send me a pull request. Bonus points for topic branches.
data/Rakefile CHANGED
@@ -2,9 +2,6 @@ require 'rake'
2
2
  require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
4
 
5
- desc 'Default: run unit tests.'
6
- task :default => :test
7
-
8
5
  desc 'Test the attr_encrypted gem.'
9
6
  Rake::TestTask.new(:test) do |t|
10
7
  t.libs << 'lib'
@@ -19,4 +16,18 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
19
16
  rdoc.options << '--line-numbers' << '--inline-source'
20
17
  rdoc.rdoc_files.include('README*')
21
18
  rdoc.rdoc_files.include('lib/**/*.rb')
22
- end
19
+ end
20
+
21
+ if RUBY_VERSION < '1.9.3'
22
+ require 'rcov/rcovtask'
23
+
24
+ task :rcov do
25
+ system "rcov -o coverage/rcov --exclude '^(?!lib)' " + FileList[ 'test/**/*_test.rb' ].join(' ')
26
+ end
27
+
28
+ desc 'Default: run unit tests under rcov.'
29
+ task :default => :rcov
30
+ else
31
+ desc 'Default: run unit tests.'
32
+ task :default => :test
33
+ end
@@ -69,6 +69,12 @@ module AttrEncrypted
69
69
  # method then the result of the method will be evaluated. Any objects that respond to <tt>:call</tt> are evaluated as well.
70
70
  # Defaults to false.
71
71
  #
72
+ # :mode => Selects encryption mode for attribute: choose <tt>:single_iv_and_salt</tt> for compatibility
73
+ # with the old attr_encrypted API: the default IV and salt of the underlying encryptor object
74
+ # is used; <tt>:per_attribute_iv_and_salt</tt> uses a per-attribute IV and salt attribute and
75
+ # is the recommended mode for new deployments.
76
+ # Defaults to <tt>:single_iv_and_salt</tt>.
77
+ #
72
78
  # You can specify your own default options
73
79
  #
74
80
  # class User
@@ -110,7 +116,8 @@ module AttrEncrypted
110
116
  :load_method => 'load',
111
117
  :encryptor => Encryptor,
112
118
  :encrypt_method => 'encrypt',
113
- :decrypt_method => 'decrypt'
119
+ :decrypt_method => 'decrypt',
120
+ :mode => :single_iv_and_salt
114
121
  }.merge!(attr_encrypted_options).merge!(attributes.last.is_a?(Hash) ? attributes.pop : {})
115
122
 
116
123
  options[:encode] = options[:default_encoding] if options[:encode] == true
@@ -122,11 +129,29 @@ module AttrEncrypted
122
129
  attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
123
130
  attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")
124
131
 
132
+ if options[:mode] == :per_attribute_iv_and_salt
133
+ attr_reader (encrypted_attribute_name.to_s + "_iv").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_iv").to_sym )
134
+ attr_writer (encrypted_attribute_name.to_s + "_iv").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_iv").to_sym )
135
+
136
+ attr_reader (encrypted_attribute_name.to_s + "_salt").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_salt").to_sym )
137
+ attr_writer (encrypted_attribute_name.to_s + "_salt").to_sym unless instance_methods_as_symbols.include?((encrypted_attribute_name.to_s + "_salt").to_sym )
138
+ end
139
+
125
140
  define_method(attribute) do
141
+ if options[:mode] == :per_attribute_iv_and_salt
142
+ load_iv_for_attribute(attribute,encrypted_attribute_name, options[:algorithm])
143
+ load_salt_for_attribute(attribute,encrypted_attribute_name)
144
+ end
145
+
126
146
  instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", decrypt(attribute, send(encrypted_attribute_name)))
127
147
  end
128
148
 
129
149
  define_method("#{attribute}=") do |value|
150
+ if options[:mode] == :per_attribute_iv_and_salt
151
+ load_iv_for_attribute(attribute, encrypted_attribute_name, options[:algorithm])
152
+ load_salt_for_attribute(attribute, encrypted_attribute_name)
153
+ end
154
+
130
155
  send("#{encrypted_attribute_name}=", encrypt(attribute, value))
131
156
  instance_variable_set("@#{attribute}", value)
132
157
  end
@@ -300,6 +325,25 @@ module AttrEncrypted
300
325
  option
301
326
  end
302
327
  end
328
+
329
+ def load_iv_for_attribute (attribute, encrypted_attribute_name, algorithm)
330
+ iv = send("#{encrypted_attribute_name.to_s + "_iv"}")
331
+ if(iv == nil)
332
+ begin
333
+ algorithm = algorithm || "aes-256-cbc"
334
+ algo = OpenSSL::Cipher::Cipher.new(algorithm)
335
+ iv = [algo.random_iv].pack("m")
336
+ send("#{encrypted_attribute_name.to_s + "_iv"}=", iv)
337
+ rescue RuntimeError
338
+ end
339
+ end
340
+ self.class.encrypted_attributes[attribute.to_sym] = self.class.encrypted_attributes[attribute.to_sym].merge(:iv => iv.unpack("m").first) if (iv && !iv.empty?)
341
+ end
342
+
343
+ def load_salt_for_attribute(attribute, encrypted_attribute_name)
344
+ salt = send("#{encrypted_attribute_name.to_s + "_salt"}") || send("#{encrypted_attribute_name.to_s + "_salt"}=", Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15])
345
+ self.class.encrypted_attributes[attribute.to_sym] = self.class.encrypted_attributes[attribute.to_sym].merge(:salt => salt)
346
+ end
303
347
  end
304
348
  end
305
349
 
@@ -6,6 +6,14 @@ if defined?(ActiveRecord::Base)
6
6
  base.class_eval do
7
7
  attr_encrypted_options[:encode] = true
8
8
  class << self; alias_method_chain :method_missing, :attr_encrypted; end
9
+
10
+ def assign_attributes_with_attr_encrypted(*args)
11
+ attributes = args.shift
12
+ encrypted_attributes = self.class.encrypted_attributes.keys
13
+ assign_attributes_without_attr_encrypted attributes.except(*encrypted_attributes), *args
14
+ assign_attributes_without_attr_encrypted attributes.slice(*encrypted_attributes), *args
15
+ end
16
+ alias_method_chain :assign_attributes, :attr_encrypted
9
17
  end
10
18
  end
11
19
 
@@ -16,6 +24,7 @@ if defined?(ActiveRecord::Base)
16
24
  def attr_encrypted(*attrs)
17
25
  define_attribute_methods rescue nil
18
26
  super
27
+ undefine_attribute_methods
19
28
  attrs.reject { |attr| attr.is_a?(Hash) }.each { |attr| alias_method "#{attr}_before_type_cast", attr }
20
29
  end
21
30
 
@@ -2,8 +2,8 @@ module AttrEncrypted
2
2
  # Contains information about this gem's version
3
3
  module Version
4
4
  MAJOR = 1
5
- MINOR = 2
6
- PATCH = 1
5
+ MINOR = 3
6
+ PATCH = 0
7
7
 
8
8
  # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
9
9
  #
@@ -1,62 +1,71 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require File.expand_path('../test_helper', __FILE__)
3
2
 
4
3
  ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
5
4
 
6
- def create_people_table
5
+ def create_tables
7
6
  silence_stream(STDOUT) do
8
7
  ActiveRecord::Schema.define(:version => 1) do
9
8
  create_table :people do |t|
10
9
  t.string :encrypted_email
11
10
  t.string :password
12
11
  t.string :encrypted_credentials
13
- t.string :salt
12
+ t.binary :salt
13
+ t.string :encrypted_email_salt
14
+ t.string :encrypted_credentials_salt
15
+ t.string :encrypted_email_iv
16
+ t.string :encrypted_credentials_iv
17
+ end
18
+ create_table :accounts do |t|
19
+ t.string :encrypted_password
20
+ t.string :encrypted_password_iv
21
+ t.string :encrypted_password_salt
14
22
  end
15
23
  end
16
24
  end
17
25
  end
18
26
 
19
27
  # The table needs to exist before defining the class
20
- create_people_table
28
+ create_tables
21
29
 
22
30
  ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
23
31
 
24
32
  class Person < ActiveRecord::Base
25
- attr_encrypted :email, :key => 'a secret key'
26
- attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'some private key') }, :marshal => true
33
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
34
+ attr_encrypted :email, :key => SECRET_KEY
35
+ attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => SECRET_KEY) }, :marshal => true
27
36
 
28
- ActiveSupport::Deprecation.silenced = true
29
- def after_initialize; end
30
- ActiveSupport::Deprecation.silenced = false
31
37
 
32
38
  after_initialize :initialize_salt_and_credentials
33
39
 
34
40
  protected
35
41
 
36
- def initialize_salt_and_credentials
37
- self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
38
- self.credentials ||= { :username => 'example', :password => 'test' }
39
- rescue ActiveRecord::MissingAttributeError
40
- end
42
+ def initialize_salt_and_credentials
43
+ self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15]
44
+ self.credentials ||= { :username => 'example', :password => 'test' }
45
+ end
41
46
  end
42
47
 
43
48
  class PersonWithValidation < Person
44
49
  validates_presence_of :email
45
- validates_uniqueness_of :encrypted_email
50
+ end
51
+
52
+ class Account < ActiveRecord::Base
53
+ attr_accessor :key
54
+ attr_encrypted :password, :key => Proc.new {|account| account.key}
55
+ end
56
+
57
+ class PersonWithSerialization < ActiveRecord::Base
58
+ self.table_name = 'people'
59
+ attr_encrypted :email, :key => 'a secret key'
60
+ serialize :password
46
61
  end
47
62
 
48
63
  class ActiveRecordTest < Test::Unit::TestCase
49
64
 
50
65
  def setup
51
66
  ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
52
- create_people_table
53
- end
54
-
55
- def test_should_decrypt_with_correct_encoding
56
- if defined?(Encoding)
57
- @person = Person.create :email => 'test@example.com'
58
- assert_equal 'UTF-8', Person.find(:first).email.encoding.name
59
- end
67
+ create_tables
68
+ Account.create!(:key => SECRET_KEY, :password => "password")
60
69
  end
61
70
 
62
71
  def test_should_encrypt_email
@@ -73,28 +82,6 @@ class ActiveRecordTest < Test::Unit::TestCase
73
82
  assert_equal @person.credentials, Person.find(:first).credentials
74
83
  end
75
84
 
76
- def test_should_find_by_email
77
- @person = Person.create(:email => 'test@example.com')
78
- assert_equal @person, Person.find_by_email('test@example.com')
79
- end
80
-
81
- def test_should_find_by_email_and_password
82
- Person.create(:email => 'test@example.com', :password => 'invalid')
83
- @person = Person.create(:email => 'test@example.com', :password => 'test')
84
- assert_equal @person, Person.find_by_email_and_password('test@example.com', 'test')
85
- end
86
-
87
- def test_should_scope_by_email
88
- @person = Person.create(:email => 'test@example.com')
89
- assert_equal @person, Person.scoped_by_email('test@example.com').find(:first) rescue NoMethodError
90
- end
91
-
92
- def test_should_scope_by_email_and_password
93
- Person.create(:email => 'test@example.com', :password => 'invalid')
94
- @person = Person.create(:email => 'test@example.com', :password => 'test')
95
- assert_equal @person, Person.scoped_by_email_and_password('test@example.com', 'test').find(:first) rescue NoMethodError
96
- end
97
-
98
85
  def test_should_encode_by_default
99
86
  assert Person.attr_encrypted_options[:encode]
100
87
  end
@@ -105,12 +92,21 @@ class ActiveRecordTest < Test::Unit::TestCase
105
92
  assert !@person.errors[:email].empty? || @person.errors.on(:email)
106
93
  end
107
94
 
108
- def test_should_validate_uniqueness_of_email
109
- @person = PersonWithValidation.new :email => 'test@example.com'
110
- assert @person.save
111
- @person2 = PersonWithValidation.new :email => @person.email
112
- assert !@person2.valid?
113
- assert !@person2.errors[:encrypted_email].empty? || @person2.errors.on(:encrypted_email)
95
+ def test_should_encrypt_decrypt_with_iv
96
+ @person = Person.create :email => 'test@example.com'
97
+ @person2 = Person.find(@person.id)
98
+ assert_not_nil @person2.encrypted_email_iv
99
+ assert_equal 'test@example.com', @person2.email
100
+ end
101
+
102
+ def test_should_ensure_attributes_can_be_deserialized
103
+ @person = PersonWithSerialization.new :email => 'test@example.com', :password => %w(an array of strings)
104
+ @person.save
105
+ assert_equal @person.password, %w(an array of strings)
114
106
  end
115
107
 
116
- end
108
+ def test_should_create_an_account_regardless_of_arguments_order
109
+ Account.create!(:key => SECRET_KEY, :password => "password")
110
+ Account.create!(:password => "password" , :key => SECRET_KEY)
111
+ end
112
+ end
@@ -1,4 +1,4 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: UTF-8
2
2
  require File.expand_path('../test_helper', __FILE__)
3
3
 
4
4
  class SillyEncryptor
@@ -12,22 +12,23 @@ class SillyEncryptor
12
12
  end
13
13
 
14
14
  class User
15
- self.attr_encrypted_options[:key] = Proc.new { |user| user.class.to_s } # default key
15
+ self.attr_encrypted_options[:key] = Proc.new { |user| SECRET_KEY } # default key
16
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
16
17
 
17
- attr_encrypted :email, :without_encoding, :key => 'secret key'
18
+ attr_encrypted :email, :without_encoding, :key => SECRET_KEY
18
19
  attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
19
- attr_encrypted :ssn, :key => :salt, :attribute => 'ssn_encrypted'
20
+ attr_encrypted :ssn, :key => :secret_key, :attribute => 'ssn_encrypted'
20
21
  attr_encrypted :credit_card, :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt, :some_arg => 'test'
21
- attr_encrypted :with_encoding, :key => 'secret key', :encode => true
22
- attr_encrypted :with_custom_encoding, :key => 'secret key', :encode => 'm'
23
- attr_encrypted :with_marshaling, :key => 'secret key', :marshal => true
24
- attr_encrypted :with_true_if, :key => 'secret key', :if => true
25
- attr_encrypted :with_false_if, :key => 'secret key', :if => false
26
- attr_encrypted :with_true_unless, :key => 'secret key', :unless => true
27
- attr_encrypted :with_false_unless, :key => 'secret key', :unless => false
28
- attr_encrypted :with_if_changed, :key => 'secret key', :if => :should_encrypt
22
+ attr_encrypted :with_encoding, :key => SECRET_KEY, :encode => true
23
+ attr_encrypted :with_custom_encoding, :key => SECRET_KEY, :encode => 'm'
24
+ attr_encrypted :with_marshaling, :key => SECRET_KEY, :marshal => true
25
+ attr_encrypted :with_true_if, :key => SECRET_KEY, :if => true
26
+ attr_encrypted :with_false_if, :key => SECRET_KEY, :if => false
27
+ attr_encrypted :with_true_unless, :key => SECRET_KEY, :unless => true
28
+ attr_encrypted :with_false_unless, :key => SECRET_KEY, :unless => false
29
+ attr_encrypted :with_if_changed, :key => SECRET_KEY, :if => :should_encrypt
29
30
 
30
- attr_encryptor :aliased, :key => 'secret_key'
31
+ attr_encryptor :aliased, :key => SECRET_KEY
31
32
 
32
33
  attr_accessor :salt
33
34
  attr_accessor :should_encrypt
@@ -36,6 +37,10 @@ class User
36
37
  self.salt = Time.now.to_i.to_s
37
38
  self.should_encrypt = true
38
39
  end
40
+
41
+ def secret_key
42
+ SECRET_KEY
43
+ end
39
44
  end
40
45
 
41
46
  class Admin < User
@@ -134,35 +139,20 @@ class AttrEncryptedTest < Test::Unit::TestCase
134
139
  assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
135
140
  end
136
141
 
137
- def test_should_decrypt_utf8_with_encoding
138
- encrypted = User.encrypt_with_encoding("test\xC2\xA0utf-8\xC2\xA0text")
139
- assert_equal "test\xC2\xA0utf-8\xC2\xA0text", User.decrypt_with_encoding(encrypted)
140
- assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
141
- end
142
-
143
142
  def test_should_encrypt_with_custom_encoding
144
- assert_equal User.encrypt_with_custom_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
143
+ assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
145
144
  end
146
145
 
147
146
  def test_should_decrypt_with_custom_encoding
148
- encrypted = User.encrypt_with_custom_encoding('test')
149
- assert_equal 'test', User.decrypt_with_custom_encoding(encrypted)
150
- assert_equal User.decrypt_with_custom_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
147
+ encrypted = User.encrypt_with_encoding('test')
148
+ assert_equal 'test', User.decrypt_with_encoding(encrypted)
149
+ assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
151
150
  end
152
151
 
153
152
  def test_should_encrypt_with_marshaling
154
153
  @user = User.new
155
154
  @user.with_marshaling = [1, 2, 3]
156
155
  assert_not_nil @user.encrypted_with_marshaling
157
- assert_equal User.encrypt_with_marshaling([1, 2, 3]), @user.encrypted_with_marshaling
158
- end
159
-
160
- def test_should_decrypt_with_marshaling
161
- encrypted = User.encrypt_with_marshaling([1, 2, 3])
162
- @user = User.new
163
- assert_nil @user.with_marshaling
164
- @user.encrypted_with_marshaling = encrypted
165
- assert_equal [1, 2, 3], @user.with_marshaling
166
156
  end
167
157
 
168
158
  def test_should_use_custom_encryptor_and_crypt_method_names_and_arguments
@@ -174,7 +164,8 @@ class AttrEncryptedTest < Test::Unit::TestCase
174
164
  assert_nil @user.ssn_encrypted
175
165
  @user.ssn = 'testing'
176
166
  assert_not_nil @user.ssn_encrypted
177
- assert_equal Encryptor.encrypt(:value => 'testing', :key => @user.salt), @user.ssn_encrypted
167
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt )
168
+ assert_equal encrypted, @user.ssn_encrypted
178
169
  end
179
170
 
180
171
  def test_should_evaluate_a_key_passed_as_a_proc
@@ -182,7 +173,8 @@ class AttrEncryptedTest < Test::Unit::TestCase
182
173
  assert_nil @user.crypted_password_test
183
174
  @user.password = 'testing'
184
175
  assert_not_nil @user.crypted_password_test
185
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
176
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
177
+ assert_equal encrypted, @user.crypted_password_test
186
178
  end
187
179
 
188
180
  def test_should_use_options_found_in_the_attr_encrypted_options_attribute
@@ -190,7 +182,8 @@ class AttrEncryptedTest < Test::Unit::TestCase
190
182
  assert_nil @user.crypted_password_test
191
183
  @user.password = 'testing'
192
184
  assert_not_nil @user.crypted_password_test
193
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'User'), @user.crypted_password_test
185
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
186
+ assert_equal encrypted, @user.crypted_password_test
194
187
  end
195
188
 
196
189
  def test_should_inherit_encrypted_attributes
@@ -232,7 +225,8 @@ class AttrEncryptedTest < Test::Unit::TestCase
232
225
  assert_nil @user.encrypted_with_true_if
233
226
  @user.with_true_if = 'testing'
234
227
  assert_not_nil @user.encrypted_with_true_if
235
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_true_if
228
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_true_if_iv.unpack("m").first, :salt => @user.encrypted_with_true_if_salt)
229
+ assert_equal encrypted, @user.encrypted_with_true_if
236
230
  end
237
231
 
238
232
  def test_should_not_encrypt_with_false_if
@@ -248,7 +242,8 @@ class AttrEncryptedTest < Test::Unit::TestCase
248
242
  assert_nil @user.encrypted_with_false_unless
249
243
  @user.with_false_unless = 'testing'
250
244
  assert_not_nil @user.encrypted_with_false_unless
251
- assert_equal Encryptor.encrypt(:value => 'testing', :key => 'secret key'), @user.encrypted_with_false_unless
245
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_false_unless_iv.unpack("m").first, :salt => @user.encrypted_with_false_unless_salt)
246
+ assert_equal encrypted, @user.encrypted_with_false_unless
252
247
  end
253
248
 
254
249
  def test_should_not_encrypt_with_true_unless
@@ -268,7 +263,7 @@ class AttrEncryptedTest < Test::Unit::TestCase
268
263
  @user.with_if_changed = "encrypt_stuff"
269
264
  @user.stubs(:instance_variable_get).returns(nil)
270
265
  @user.stubs(:instance_variable_set).raises("BadStuff")
271
- assert_raise RuntimeError do
266
+ assert_raise RuntimeError do
272
267
  @user.with_if_changed
273
268
  end
274
269