attr_encrypted 1.4.0 → 2.0.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +6 -0
- data/.travis.yml +24 -0
- data/CHANGELOG.md +71 -0
- data/Gemfile +3 -0
- data/README.md +420 -0
- data/Rakefile +3 -15
- data/attr_encrypted.gemspec +60 -0
- data/certs/saghaulor.pem +21 -0
- data/lib/attr_encrypted.rb +197 -114
- data/lib/attr_encrypted/adapters/active_record.rb +8 -8
- data/lib/attr_encrypted/adapters/data_mapper.rb +1 -0
- data/lib/attr_encrypted/adapters/sequel.rb +1 -0
- data/lib/attr_encrypted/version.rb +2 -2
- data/test/active_record_test.rb +40 -18
- data/test/attr_encrypted_test.rb +101 -39
- data/test/compatibility_test.rb +19 -36
- data/test/data_mapper_test.rb +1 -1
- data/test/legacy_active_record_test.rb +11 -7
- data/test/legacy_attr_encrypted_test.rb +17 -16
- data/test/legacy_compatibility_test.rb +21 -30
- data/test/legacy_data_mapper_test.rb +6 -3
- data/test/legacy_sequel_test.rb +8 -4
- data/test/run.sh +12 -52
- data/test/sequel_test.rb +1 -1
- data/test/test_helper.rb +27 -17
- metadata +62 -28
- metadata.gz.sig +2 -0
- data/README.rdoc +0 -344
@@ -18,9 +18,7 @@ if defined?(ActiveRecord::Base)
|
|
18
18
|
attr_encrypted_options[:encode] = true
|
19
19
|
|
20
20
|
class << self
|
21
|
-
alias_method :attr_encryptor, :attr_encrypted
|
22
21
|
alias_method_chain :method_missing, :attr_encrypted
|
23
|
-
alias_method :undefine_attribute_methods, :reset_column_information if ::ActiveRecord::VERSION::STRING < "3"
|
24
22
|
end
|
25
23
|
|
26
24
|
def perform_attribute_assignment(method, new_attributes, *args)
|
@@ -31,7 +29,7 @@ if defined?(ActiveRecord::Base)
|
|
31
29
|
end
|
32
30
|
private :perform_attribute_assignment
|
33
31
|
|
34
|
-
if ::ActiveRecord::VERSION::STRING
|
32
|
+
if ::ActiveRecord::VERSION::STRING > "3.1"
|
35
33
|
def assign_attributes_with_attr_encrypted(*args)
|
36
34
|
perform_attribute_assignment :assign_attributes_without_attr_encrypted, *args
|
37
35
|
end
|
@@ -69,10 +67,10 @@ if defined?(ActiveRecord::Base)
|
|
69
67
|
# We add accessor methods of the db columns to the list of instance
|
70
68
|
# methods returned to let ActiveRecord define the accessor methods
|
71
69
|
# for the db columns
|
72
|
-
|
70
|
+
|
73
71
|
# Use with_connection so the connection doesn't stay pinned to the thread.
|
74
72
|
connected = ::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false
|
75
|
-
|
73
|
+
|
76
74
|
if connected && table_exists?
|
77
75
|
columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
|
78
76
|
else
|
@@ -85,13 +83,13 @@ if defined?(ActiveRecord::Base)
|
|
85
83
|
#
|
86
84
|
# NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
|
87
85
|
#
|
88
|
-
# This is useful for encrypting fields like email addresses. Your user's email addresses
|
86
|
+
# This is useful for encrypting fields like email addresses. Your user's email addresses
|
89
87
|
# are encrypted in the database, but you can still look up a user by email for logging in
|
90
88
|
#
|
91
89
|
# Example
|
92
90
|
#
|
93
91
|
# class User < ActiveRecord::Base
|
94
|
-
# attr_encrypted :email, :
|
92
|
+
# attr_encrypted :email, key: 'secret key'
|
95
93
|
# end
|
96
94
|
#
|
97
95
|
# User.find_by_email_and_password('test@example.com', 'testing')
|
@@ -101,8 +99,9 @@ if defined?(ActiveRecord::Base)
|
|
101
99
|
if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
|
102
100
|
attribute_names = match.captures.last.split('_and_')
|
103
101
|
attribute_names.each_with_index do |attribute, index|
|
104
|
-
if attr_encrypted?(attribute)
|
102
|
+
if attr_encrypted?(attribute) && encrypted_attributes[attribute.to_sym][:mode] == :single_iv_and_salt
|
105
103
|
args[index] = send("encrypt_#{attribute}", args[index])
|
104
|
+
warn "DEPRECATION WARNING: This feature will be removed in the next major release."
|
106
105
|
attribute_names[index] = encrypted_attributes[attribute.to_sym][:attribute]
|
107
106
|
end
|
108
107
|
end
|
@@ -114,5 +113,6 @@ if defined?(ActiveRecord::Base)
|
|
114
113
|
end
|
115
114
|
end
|
116
115
|
|
116
|
+
ActiveRecord::Base.extend AttrEncrypted
|
117
117
|
ActiveRecord::Base.extend AttrEncrypted::Adapters::ActiveRecord
|
118
118
|
end
|
data/test/active_record_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative 'test_helper'
|
2
2
|
|
3
3
|
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
|
4
4
|
|
@@ -28,6 +28,12 @@ def create_tables
|
|
28
28
|
create_table :prime_ministers do |t|
|
29
29
|
t.string :encrypted_name
|
30
30
|
end
|
31
|
+
create_table :addresses do |t|
|
32
|
+
t.binary :encrypted_street
|
33
|
+
t.binary :encrypted_street_iv
|
34
|
+
t.binary :encrypted_zipcode
|
35
|
+
t.string :mode
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|
@@ -36,7 +42,6 @@ end
|
|
36
42
|
create_tables
|
37
43
|
|
38
44
|
ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
|
39
|
-
ActiveRecord::Base.logger = Logger.new(nil) if ::ActiveRecord::VERSION::STRING < "3.0"
|
40
45
|
|
41
46
|
if ::ActiveRecord::VERSION::STRING > "4.0"
|
42
47
|
module Rack
|
@@ -51,15 +56,9 @@ end
|
|
51
56
|
class Person < ActiveRecord::Base
|
52
57
|
self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
53
58
|
attr_encrypted :email, :key => SECRET_KEY
|
54
|
-
attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => SECRET_KEY) }, :marshal => true
|
59
|
+
attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => SECRET_KEY, iv: SecureRandom.random_bytes(12)) }, :marshal => true
|
55
60
|
|
56
|
-
|
57
|
-
def after_initialize
|
58
|
-
initialize_salt_and_credentials
|
59
|
-
end
|
60
|
-
else
|
61
|
-
after_initialize :initialize_salt_and_credentials
|
62
|
-
end
|
61
|
+
after_initialize :initialize_salt_and_credentials
|
63
62
|
|
64
63
|
protected
|
65
64
|
|
@@ -75,7 +74,7 @@ end
|
|
75
74
|
|
76
75
|
class PersonWithProcMode < Person
|
77
76
|
attr_encrypted :email, :key => SECRET_KEY, :mode => Proc.new { :per_attribute_iv_and_salt }
|
78
|
-
attr_encrypted :credentials, :key => SECRET_KEY, :mode => Proc.new { :single_iv_and_salt }
|
77
|
+
attr_encrypted :credentials, :key => SECRET_KEY, :mode => Proc.new { :single_iv_and_salt }, insecure_mode: true
|
79
78
|
end
|
80
79
|
|
81
80
|
class Account < ActiveRecord::Base
|
@@ -85,23 +84,30 @@ end
|
|
85
84
|
|
86
85
|
class PersonWithSerialization < ActiveRecord::Base
|
87
86
|
self.table_name = 'people'
|
88
|
-
attr_encrypted :email, :key =>
|
87
|
+
attr_encrypted :email, :key => SECRET_KEY
|
89
88
|
serialize :password
|
90
89
|
end
|
91
90
|
|
92
91
|
class UserWithProtectedAttribute < ActiveRecord::Base
|
93
92
|
self.table_name = 'users'
|
94
|
-
attr_encrypted :password, :key =>
|
93
|
+
attr_encrypted :password, :key => SECRET_KEY
|
95
94
|
attr_protected :is_admin if ::ActiveRecord::VERSION::STRING < "4.0"
|
96
95
|
end
|
97
96
|
|
98
97
|
class PersonUsingAlias < ActiveRecord::Base
|
99
98
|
self.table_name = 'people'
|
100
|
-
attr_encryptor :email, :key =>
|
99
|
+
attr_encryptor :email, :key => SECRET_KEY
|
101
100
|
end
|
102
101
|
|
103
102
|
class PrimeMinister < ActiveRecord::Base
|
104
|
-
attr_encrypted :name, :marshal => true, :key =>
|
103
|
+
attr_encrypted :name, :marshal => true, :key => SECRET_KEY
|
104
|
+
end
|
105
|
+
|
106
|
+
class Address < ActiveRecord::Base
|
107
|
+
self.attr_encrypted_options[:marshal] = false
|
108
|
+
self.attr_encrypted_options[:encode] = false
|
109
|
+
attr_encrypted :street, encode_iv: false, key: SECRET_KEY
|
110
|
+
attr_encrypted :zipcode, key: SECRET_KEY, mode: Proc.new { |address| address.mode.to_sym }, insecure_mode: true
|
105
111
|
end
|
106
112
|
|
107
113
|
class ActiveRecordTest < Minitest::Test
|
@@ -116,14 +122,14 @@ class ActiveRecordTest < Minitest::Test
|
|
116
122
|
@person = Person.create :email => 'test@example.com'
|
117
123
|
refute_nil @person.encrypted_email
|
118
124
|
refute_equal @person.email, @person.encrypted_email
|
119
|
-
assert_equal @person.email, Person.
|
125
|
+
assert_equal @person.email, Person.first.email
|
120
126
|
end
|
121
127
|
|
122
128
|
def test_should_marshal_and_encrypt_credentials
|
123
129
|
@person = Person.create
|
124
130
|
refute_nil @person.encrypted_credentials
|
125
131
|
refute_equal @person.credentials, @person.encrypted_credentials
|
126
|
-
assert_equal @person.credentials, Person.
|
132
|
+
assert_equal @person.credentials, Person.first.credentials
|
127
133
|
end
|
128
134
|
|
129
135
|
def test_should_encode_by_default
|
@@ -155,6 +161,7 @@ class ActiveRecordTest < Minitest::Test
|
|
155
161
|
end
|
156
162
|
|
157
163
|
def test_should_set_attributes_regardless_of_arguments_order
|
164
|
+
# minitest does not implement `assert_nothing_raised` https://github.com/seattlerb/minitest/issues/112
|
158
165
|
Account.new.attributes = { :password => "password" , :key => SECRET_KEY }
|
159
166
|
end
|
160
167
|
|
@@ -263,7 +270,7 @@ class ActiveRecordTest < Minitest::Test
|
|
263
270
|
|
264
271
|
refute_nil user.encrypted_email
|
265
272
|
refute_equal user.email, user.encrypted_email
|
266
|
-
assert_equal user.email, PersonUsingAlias.
|
273
|
+
assert_equal user.email, PersonUsingAlias.first.email
|
267
274
|
end
|
268
275
|
|
269
276
|
# See https://github.com/attr-encrypted/attr_encrypted/issues/68
|
@@ -278,4 +285,19 @@ class ActiveRecordTest < Minitest::Test
|
|
278
285
|
assert_equal pm, result
|
279
286
|
assert_equal 'Winston Churchill', pm.name
|
280
287
|
end
|
288
|
+
|
289
|
+
def test_should_save_encrypted_data_as_binary
|
290
|
+
street = '123 Elm'
|
291
|
+
address = Address.new(street: street)
|
292
|
+
address.save!
|
293
|
+
refute_equal address.encrypted_street, street
|
294
|
+
assert_equal Address.first.street, street
|
295
|
+
end
|
296
|
+
|
297
|
+
def test_should_evaluate_proc_based_mode
|
298
|
+
street = '123 Elm'
|
299
|
+
zipcode = '12345'
|
300
|
+
address = Address.new(street: street, zipcode: zipcode, mode: :single_iv_and_salt)
|
301
|
+
assert_nil address.encrypted_zipcode_iv
|
302
|
+
end
|
281
303
|
end
|
data/test/attr_encrypted_test.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
2
|
+
require_relative 'test_helper'
|
3
3
|
|
4
4
|
class SillyEncryptor
|
5
5
|
def self.silly_encrypt(options)
|
@@ -12,6 +12,7 @@ class SillyEncryptor
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class User
|
15
|
+
extend AttrEncrypted
|
15
16
|
self.attr_encrypted_options[:key] = Proc.new { |user| SECRET_KEY } # default key
|
16
17
|
self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
17
18
|
|
@@ -33,7 +34,8 @@ class User
|
|
33
34
|
attr_accessor :salt
|
34
35
|
attr_accessor :should_encrypt
|
35
36
|
|
36
|
-
def initialize
|
37
|
+
def initialize(email: nil)
|
38
|
+
self.email = email
|
37
39
|
self.salt = Time.now.to_i.to_s
|
38
40
|
self.should_encrypt = true
|
39
41
|
end
|
@@ -48,19 +50,40 @@ class Admin < User
|
|
48
50
|
end
|
49
51
|
|
50
52
|
class SomeOtherClass
|
53
|
+
extend AttrEncrypted
|
51
54
|
def self.call(object)
|
52
55
|
object.class
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
59
|
+
class YetAnotherClass
|
60
|
+
extend AttrEncrypted
|
61
|
+
self.attr_encrypted_options[:encode_iv] = false
|
62
|
+
|
63
|
+
attr_encrypted :email, :key => SECRET_KEY
|
64
|
+
attr_encrypted :phone_number, :key => SECRET_KEY, mode: Proc.new { |thing| thing.mode }, encode_iv: Proc.new { |thing| thing.encode_iv }, encode_salt: Proc.new { |thing| thing.encode_salt }
|
65
|
+
|
66
|
+
def initialize(email: nil, encode_iv: 'm', encode_salt: 'm', mode: :per_attribute_iv_and_salt)
|
67
|
+
self.email = email
|
68
|
+
@encode_iv = encode_iv
|
69
|
+
@encode_salt = encode_salt
|
70
|
+
@mode = mode
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_reader :encode_iv, :encode_salt, :mode
|
74
|
+
end
|
75
|
+
|
56
76
|
class AttrEncryptedTest < Minitest::Test
|
77
|
+
def setup
|
78
|
+
@iv = SecureRandom.random_bytes(12)
|
79
|
+
end
|
57
80
|
|
58
81
|
def test_should_store_email_in_encrypted_attributes
|
59
82
|
assert User.encrypted_attributes.include?(:email)
|
60
83
|
end
|
61
84
|
|
62
85
|
def test_should_not_store_salt_in_encrypted_attributes
|
63
|
-
|
86
|
+
refute User.encrypted_attributes.include?(:salt)
|
64
87
|
end
|
65
88
|
|
66
89
|
def test_attr_encrypted_should_return_true_for_email
|
@@ -88,16 +111,16 @@ class AttrEncryptedTest < Minitest::Test
|
|
88
111
|
end
|
89
112
|
|
90
113
|
def test_should_not_encrypt_nil_value
|
91
|
-
assert_nil User.encrypt_email(nil)
|
114
|
+
assert_nil User.encrypt_email(nil, iv: @iv)
|
92
115
|
end
|
93
116
|
|
94
117
|
def test_should_not_encrypt_empty_string
|
95
|
-
assert_equal '', User.encrypt_email('')
|
118
|
+
assert_equal '', User.encrypt_email('', iv: @iv)
|
96
119
|
end
|
97
120
|
|
98
121
|
def test_should_encrypt_email
|
99
|
-
refute_nil User.encrypt_email('test@example.com')
|
100
|
-
refute_equal 'test@example.com', User.encrypt_email('test@example.com')
|
122
|
+
refute_nil User.encrypt_email('test@example.com', iv: @iv)
|
123
|
+
refute_equal 'test@example.com', User.encrypt_email('test@example.com', iv: @iv)
|
101
124
|
end
|
102
125
|
|
103
126
|
def test_should_encrypt_email_when_modifying_the_attr_writer
|
@@ -105,48 +128,52 @@ class AttrEncryptedTest < Minitest::Test
|
|
105
128
|
assert_nil @user.encrypted_email
|
106
129
|
@user.email = 'test@example.com'
|
107
130
|
refute_nil @user.encrypted_email
|
108
|
-
|
131
|
+
iv = @user.encrypted_email_iv.unpack('m').first
|
132
|
+
salt = @user.encrypted_email_salt[1..-1].unpack('m').first
|
133
|
+
assert_equal User.encrypt_email('test@example.com', iv: iv, salt: salt), @user.encrypted_email
|
109
134
|
end
|
110
135
|
|
111
136
|
def test_should_not_decrypt_nil_value
|
112
|
-
assert_nil User.decrypt_email(nil)
|
137
|
+
assert_nil User.decrypt_email(nil, iv: @iv)
|
113
138
|
end
|
114
139
|
|
115
140
|
def test_should_not_decrypt_empty_string
|
116
|
-
assert_equal '', User.decrypt_email('')
|
141
|
+
assert_equal '', User.decrypt_email('', iv: @iv)
|
117
142
|
end
|
118
143
|
|
119
144
|
def test_should_decrypt_email
|
120
|
-
encrypted_email = User.encrypt_email('test@example.com')
|
145
|
+
encrypted_email = User.encrypt_email('test@example.com', iv: @iv)
|
121
146
|
refute_equal 'test@test.com', encrypted_email
|
122
|
-
assert_equal 'test@example.com', User.decrypt_email(encrypted_email)
|
147
|
+
assert_equal 'test@example.com', User.decrypt_email(encrypted_email, iv: @iv)
|
123
148
|
end
|
124
149
|
|
125
150
|
def test_should_decrypt_email_when_reading
|
126
151
|
@user = User.new
|
127
152
|
assert_nil @user.email
|
128
|
-
|
153
|
+
iv = @user.encrypted_email_iv.unpack('m').first
|
154
|
+
salt = @user.encrypted_email_salt[1..-1].unpack('m').first
|
155
|
+
@user.encrypted_email = User.encrypt_email('test@example.com', iv: iv, salt: salt)
|
129
156
|
assert_equal 'test@example.com', @user.email
|
130
157
|
end
|
131
158
|
|
132
159
|
def test_should_encrypt_with_encoding
|
133
|
-
assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
|
160
|
+
assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
|
134
161
|
end
|
135
162
|
|
136
163
|
def test_should_decrypt_with_encoding
|
137
|
-
encrypted = User.encrypt_with_encoding('test')
|
138
|
-
assert_equal 'test', User.decrypt_with_encoding(encrypted)
|
139
|
-
assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
|
164
|
+
encrypted = User.encrypt_with_encoding('test', iv: @iv)
|
165
|
+
assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
|
166
|
+
assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
|
140
167
|
end
|
141
168
|
|
142
169
|
def test_should_encrypt_with_custom_encoding
|
143
|
-
assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
|
170
|
+
assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
|
144
171
|
end
|
145
172
|
|
146
173
|
def test_should_decrypt_with_custom_encoding
|
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)
|
174
|
+
encrypted = User.encrypt_with_encoding('test', iv: @iv)
|
175
|
+
assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
|
176
|
+
assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
|
150
177
|
end
|
151
178
|
|
152
179
|
def test_should_encrypt_with_marshaling
|
@@ -164,7 +191,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
164
191
|
assert_nil @user.ssn_encrypted
|
165
192
|
@user.ssn = 'testing'
|
166
193
|
refute_nil @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 )
|
194
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt.unpack("m").first )
|
168
195
|
assert_equal encrypted, @user.ssn_encrypted
|
169
196
|
end
|
170
197
|
|
@@ -173,7 +200,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
173
200
|
assert_nil @user.crypted_password_test
|
174
201
|
@user.password = 'testing'
|
175
202
|
refute_nil @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)
|
203
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
|
177
204
|
assert_equal encrypted, @user.crypted_password_test
|
178
205
|
end
|
179
206
|
|
@@ -182,7 +209,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
182
209
|
assert_nil @user.crypted_password_test
|
183
210
|
@user.password = 'testing'
|
184
211
|
refute_nil @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)
|
212
|
+
encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
|
186
213
|
assert_equal encrypted, @user.crypted_password_test
|
187
214
|
end
|
188
215
|
|
@@ -201,23 +228,24 @@ class AttrEncryptedTest < Minitest::Test
|
|
201
228
|
end
|
202
229
|
|
203
230
|
def test_should_evaluate_a_symbol_option
|
204
|
-
assert_equal
|
231
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, :class)
|
205
232
|
end
|
206
233
|
|
207
234
|
def test_should_evaluate_a_proc_option
|
208
|
-
assert_equal
|
235
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
|
209
236
|
end
|
210
237
|
|
211
238
|
def test_should_evaluate_a_lambda_option
|
212
|
-
assert_equal
|
239
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
|
213
240
|
end
|
214
241
|
|
215
242
|
def test_should_evaluate_a_method_option
|
216
|
-
assert_equal
|
243
|
+
assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call))
|
217
244
|
end
|
218
245
|
|
219
246
|
def test_should_return_a_string_option
|
220
|
-
|
247
|
+
class_string = 'SomeOtherClass'
|
248
|
+
assert_equal class_string, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, class_string)
|
221
249
|
end
|
222
250
|
|
223
251
|
def test_should_encrypt_with_true_if
|
@@ -225,7 +253,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
225
253
|
assert_nil @user.encrypted_with_true_if
|
226
254
|
@user.with_true_if = 'testing'
|
227
255
|
refute_nil @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)
|
256
|
+
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.unpack("m").first)
|
229
257
|
assert_equal encrypted, @user.encrypted_with_true_if
|
230
258
|
end
|
231
259
|
|
@@ -242,7 +270,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
242
270
|
assert_nil @user.encrypted_with_false_unless
|
243
271
|
@user.with_false_unless = 'testing'
|
244
272
|
refute_nil @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)
|
273
|
+
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.unpack("m").first)
|
246
274
|
assert_equal encrypted, @user.encrypted_with_false_unless
|
247
275
|
end
|
248
276
|
|
@@ -261,11 +289,6 @@ class AttrEncryptedTest < Minitest::Test
|
|
261
289
|
def test_should_always_reset_options
|
262
290
|
@user = User.new
|
263
291
|
@user.with_if_changed = "encrypt_stuff"
|
264
|
-
@user.stubs(:instance_variable_get).returns(nil)
|
265
|
-
@user.stubs(:instance_variable_set).raises("BadStuff")
|
266
|
-
assert_raises RuntimeError do
|
267
|
-
@user.with_if_changed
|
268
|
-
end
|
269
292
|
|
270
293
|
@user = User.new
|
271
294
|
@user.should_encrypt = false
|
@@ -275,9 +298,9 @@ class AttrEncryptedTest < Minitest::Test
|
|
275
298
|
end
|
276
299
|
|
277
300
|
def test_should_cast_values_as_strings_before_encrypting
|
278
|
-
string_encrypted_email = User.encrypt_email('3')
|
279
|
-
assert_equal string_encrypted_email, User.encrypt_email(3)
|
280
|
-
assert_equal '3', User.decrypt_email(string_encrypted_email)
|
301
|
+
string_encrypted_email = User.encrypt_email('3', iv: @iv)
|
302
|
+
assert_equal string_encrypted_email, User.encrypt_email(3, iv: @iv)
|
303
|
+
assert_equal '3', User.decrypt_email(string_encrypted_email, iv: @iv)
|
281
304
|
end
|
282
305
|
|
283
306
|
def test_should_create_query_accessor
|
@@ -296,12 +319,18 @@ class AttrEncryptedTest < Minitest::Test
|
|
296
319
|
refute_equal @user.encrypted_email_iv, @user.crypted_password_test_iv
|
297
320
|
end
|
298
321
|
|
322
|
+
def test_should_generate_iv_per_attribute_by_default
|
323
|
+
thing = YetAnotherClass.new(email: 'thing@thing.com')
|
324
|
+
refute_nil thing.encrypted_email_iv
|
325
|
+
end
|
326
|
+
|
299
327
|
def test_should_vary_iv_per_instance
|
300
328
|
@user1 = User.new
|
301
329
|
@user1.email = 'email@example.com'
|
302
330
|
@user2 = User.new
|
303
331
|
@user2.email = 'email@example.com'
|
304
332
|
refute_equal @user1.encrypted_email_iv, @user2.encrypted_email_iv
|
333
|
+
refute_equal @user1.encrypted_email, @user2.encrypted_email
|
305
334
|
end
|
306
335
|
|
307
336
|
def test_should_vary_salt_per_attribute
|
@@ -319,6 +348,11 @@ class AttrEncryptedTest < Minitest::Test
|
|
319
348
|
refute_equal @user1.encrypted_email_salt, @user2.encrypted_email_salt
|
320
349
|
end
|
321
350
|
|
351
|
+
def test_should_not_generate_salt_per_attribute_by_default
|
352
|
+
thing = YetAnotherClass.new(email: 'thing@thing.com')
|
353
|
+
assert_nil thing.encrypted_email_salt
|
354
|
+
end
|
355
|
+
|
322
356
|
def test_should_decrypt_second_record
|
323
357
|
@user1 = User.new
|
324
358
|
@user1.email = 'test@example.com'
|
@@ -328,4 +362,32 @@ class AttrEncryptedTest < Minitest::Test
|
|
328
362
|
|
329
363
|
assert_equal 'test@example.com', @user1.decrypt(:email, @user1.encrypted_email)
|
330
364
|
end
|
365
|
+
|
366
|
+
def test_should_specify_the_default_algorithm
|
367
|
+
assert YetAnotherClass.encrypted_attributes[:email][:algorithm]
|
368
|
+
assert_equal YetAnotherClass.encrypted_attributes[:email][:algorithm], 'aes-256-gcm'
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_should_not_encode_iv_when_encode_iv_is_false
|
372
|
+
email = 'thing@thing.com'
|
373
|
+
thing = YetAnotherClass.new(email: email)
|
374
|
+
refute thing.encrypted_email_iv =~ base64_encoding_regex
|
375
|
+
assert_equal thing.email, email
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_should_base64_encode_iv_by_default
|
379
|
+
phone_number = '555-555-5555'
|
380
|
+
thing = YetAnotherClass.new
|
381
|
+
thing.phone_number = phone_number
|
382
|
+
assert thing.encrypted_phone_number_iv =~ base64_encoding_regex
|
383
|
+
assert_equal thing.phone_number, phone_number
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_should_generate_unique_iv_for_every_encrypt_operation
|
387
|
+
user = User.new
|
388
|
+
user.email = 'initial_value@test.com'
|
389
|
+
original_iv = user.encrypted_email_iv
|
390
|
+
user.email = 'revised_value@test.com'
|
391
|
+
refute_equal original_iv, user.encrypted_email_iv
|
392
|
+
end
|
331
393
|
end
|