attr_encrypted 1.3.3 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +6 -0
- data/.travis.yml +24 -0
- data/CHANGELOG.md +79 -0
- data/Gemfile +3 -0
- data/README.md +444 -0
- data/Rakefile +4 -15
- data/attr_encrypted.gemspec +63 -0
- data/certs/saghaulor.pem +21 -0
- data/checksum/attr_encrypted-3.0.0.gem.sha256 +1 -0
- data/checksum/attr_encrypted-3.0.0.gem.sha512 +1 -0
- data/lib/attr_encrypted.rb +196 -105
- data/lib/attr_encrypted/adapters/active_record.rb +64 -21
- 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 +3 -3
- data/test/active_record_test.rb +157 -57
- data/test/attr_encrypted_test.rb +117 -55
- data/test/compatibility_test.rb +20 -37
- data/test/data_mapper_test.rb +6 -6
- data/test/legacy_active_record_test.rb +16 -12
- data/test/legacy_attr_encrypted_test.rb +31 -30
- data/test/legacy_compatibility_test.rb +22 -31
- data/test/legacy_data_mapper_test.rb +11 -8
- data/test/legacy_sequel_test.rb +13 -9
- data/test/run.sh +12 -52
- data/test/sequel_test.rb +6 -6
- data/test/test_helper.rb +28 -16
- metadata +121 -70
- metadata.gz.sig +0 -0
- data/README.rdoc +0 -302
@@ -4,59 +4,100 @@ if defined?(ActiveRecord::Base)
|
|
4
4
|
module ActiveRecord
|
5
5
|
def self.extended(base) # :nodoc:
|
6
6
|
base.class_eval do
|
7
|
+
|
8
|
+
# https://github.com/attr-encrypted/attr_encrypted/issues/68
|
9
|
+
def reload_with_attr_encrypted(*args, &block)
|
10
|
+
result = reload_without_attr_encrypted(*args, &block)
|
11
|
+
self.class.encrypted_attributes.keys.each do |attribute_name|
|
12
|
+
instance_variable_set("@#{attribute_name}", nil)
|
13
|
+
end
|
14
|
+
result
|
15
|
+
end
|
16
|
+
alias_method_chain :reload, :attr_encrypted
|
17
|
+
|
7
18
|
attr_encrypted_options[:encode] = true
|
19
|
+
|
8
20
|
class << self
|
9
|
-
alias_method :attr_encryptor, :attr_encrypted
|
10
21
|
alias_method_chain :method_missing, :attr_encrypted
|
11
|
-
alias_method :undefine_attribute_methods, :reset_column_information if ::ActiveRecord::VERSION::STRING < "3"
|
12
22
|
end
|
13
23
|
|
14
24
|
def perform_attribute_assignment(method, new_attributes, *args)
|
15
25
|
return if new_attributes.blank?
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
self.send method, attributes.slice(*encrypted_attributes), *args
|
26
|
+
|
27
|
+
send method, new_attributes.reject { |k, _| self.class.encrypted_attributes.key?(k.to_sym) }, *args
|
28
|
+
send method, new_attributes.reject { |k, _| !self.class.encrypted_attributes.key?(k.to_sym) }, *args
|
20
29
|
end
|
21
30
|
private :perform_attribute_assignment
|
22
31
|
|
23
|
-
if ::ActiveRecord::VERSION::STRING
|
32
|
+
if ::ActiveRecord::VERSION::STRING > "3.1"
|
24
33
|
def assign_attributes_with_attr_encrypted(*args)
|
25
34
|
perform_attribute_assignment :assign_attributes_without_attr_encrypted, *args
|
26
35
|
end
|
27
36
|
alias_method_chain :assign_attributes, :attr_encrypted
|
28
|
-
else
|
29
|
-
def attributes_with_attr_encrypted=(*args)
|
30
|
-
perform_attribute_assignment :attributes_without_attr_encrypted=, *args
|
31
|
-
end
|
32
|
-
alias_method_chain :attributes=, :attr_encrypted
|
33
37
|
end
|
38
|
+
|
39
|
+
def attributes_with_attr_encrypted=(*args)
|
40
|
+
perform_attribute_assignment :attributes_without_attr_encrypted=, *args
|
41
|
+
end
|
42
|
+
alias_method_chain :attributes=, :attr_encrypted
|
34
43
|
end
|
35
44
|
end
|
36
45
|
|
37
46
|
protected
|
38
47
|
|
39
|
-
# Ensures the attribute methods for db fields have been defined before calling the original
|
40
48
|
# <tt>attr_encrypted</tt> method
|
41
49
|
def attr_encrypted(*attrs)
|
42
|
-
define_attribute_methods rescue nil
|
43
50
|
super
|
44
|
-
|
45
|
-
|
51
|
+
options = attrs.extract_options!
|
52
|
+
attr = attrs.pop
|
53
|
+
options.merge! encrypted_attributes[attr]
|
54
|
+
|
55
|
+
define_method("#{attr}_changed?") do
|
56
|
+
if send("#{options[:attribute]}_changed?")
|
57
|
+
send(attr) != send("#{attr}_was")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
define_method("#{attr}_was") do
|
62
|
+
attr_was_options = { operation: :decrypting }
|
63
|
+
attr_was_options[:iv]= send("#{options[:attribute]}_iv_was") if respond_to?("#{options[:attribute]}_iv_was")
|
64
|
+
attr_was_options[:salt]= send("#{options[:attribute]}_salt_was") if respond_to?("#{options[:attribute]}_salt_was")
|
65
|
+
encrypted_attributes[attr].merge!(attr_was_options)
|
66
|
+
evaluated_options = evaluated_attr_encrypted_options_for(attr)
|
67
|
+
[:iv, :salt, :operation].each { |key| encrypted_attributes[attr].delete(key) }
|
68
|
+
self.class.decrypt(attr, send("#{options[:attribute]}_was"), evaluated_options)
|
69
|
+
end
|
70
|
+
|
71
|
+
alias_method "#{attr}_before_type_cast", attr
|
72
|
+
end
|
73
|
+
|
74
|
+
def attribute_instance_methods_as_symbols
|
75
|
+
# We add accessor methods of the db columns to the list of instance
|
76
|
+
# methods returned to let ActiveRecord define the accessor methods
|
77
|
+
# for the db columns
|
78
|
+
|
79
|
+
# Use with_connection so the connection doesn't stay pinned to the thread.
|
80
|
+
connected = ::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false
|
81
|
+
|
82
|
+
if connected && table_exists?
|
83
|
+
columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
46
87
|
end
|
47
88
|
|
48
|
-
# Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
|
89
|
+
# Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
|
49
90
|
# encrypted attributes
|
50
91
|
#
|
51
92
|
# NOTE: This only works when the <tt>:key</tt> option is specified as a string (see the README)
|
52
93
|
#
|
53
|
-
# This is useful for encrypting fields like email addresses. Your user's email addresses
|
94
|
+
# This is useful for encrypting fields like email addresses. Your user's email addresses
|
54
95
|
# are encrypted in the database, but you can still look up a user by email for logging in
|
55
96
|
#
|
56
97
|
# Example
|
57
98
|
#
|
58
99
|
# class User < ActiveRecord::Base
|
59
|
-
# attr_encrypted :email, :
|
100
|
+
# attr_encrypted :email, key: 'secret key'
|
60
101
|
# end
|
61
102
|
#
|
62
103
|
# User.find_by_email_and_password('test@example.com', 'testing')
|
@@ -66,8 +107,9 @@ if defined?(ActiveRecord::Base)
|
|
66
107
|
if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
|
67
108
|
attribute_names = match.captures.last.split('_and_')
|
68
109
|
attribute_names.each_with_index do |attribute, index|
|
69
|
-
if attr_encrypted?(attribute)
|
110
|
+
if attr_encrypted?(attribute) && encrypted_attributes[attribute.to_sym][:mode] == :single_iv_and_salt
|
70
111
|
args[index] = send("encrypt_#{attribute}", args[index])
|
112
|
+
warn "DEPRECATION WARNING: This feature will be removed in the next major release."
|
71
113
|
attribute_names[index] = encrypted_attributes[attribute.to_sym][:attribute]
|
72
114
|
end
|
73
115
|
end
|
@@ -79,5 +121,6 @@ if defined?(ActiveRecord::Base)
|
|
79
121
|
end
|
80
122
|
end
|
81
123
|
|
124
|
+
ActiveRecord::Base.extend AttrEncrypted
|
82
125
|
ActiveRecord::Base.extend AttrEncrypted::Adapters::ActiveRecord
|
83
|
-
end
|
126
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module AttrEncrypted
|
2
2
|
# Contains information about this gem's version
|
3
3
|
module Version
|
4
|
-
MAJOR =
|
5
|
-
MINOR =
|
6
|
-
PATCH =
|
4
|
+
MAJOR = 3
|
5
|
+
MINOR = 0
|
6
|
+
PATCH = 1
|
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
|
#
|
data/test/active_record_test.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
|
1
|
+
require_relative 'test_helper'
|
2
2
|
|
3
|
-
ActiveRecord::Base.establish_connection
|
3
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
4
4
|
|
5
5
|
def create_tables
|
6
6
|
silence_stream(STDOUT) do
|
7
|
-
ActiveRecord::Schema.define(:
|
7
|
+
ActiveRecord::Schema.define(version: 1) do
|
8
8
|
create_table :people do |t|
|
9
9
|
t.string :encrypted_email
|
10
10
|
t.string :password
|
11
11
|
t.string :encrypted_credentials
|
12
12
|
t.binary :salt
|
13
|
+
t.binary :key_iv
|
13
14
|
t.string :encrypted_email_salt
|
14
15
|
t.string :encrypted_credentials_salt
|
15
16
|
t.string :encrypted_email_iv
|
@@ -23,8 +24,19 @@ def create_tables
|
|
23
24
|
create_table :users do |t|
|
24
25
|
t.string :login
|
25
26
|
t.string :encrypted_password
|
27
|
+
t.string :encrypted_password_iv
|
26
28
|
t.boolean :is_admin
|
27
29
|
end
|
30
|
+
create_table :prime_ministers do |t|
|
31
|
+
t.string :encrypted_name
|
32
|
+
t.string :encrypted_name_iv
|
33
|
+
end
|
34
|
+
create_table :addresses do |t|
|
35
|
+
t.binary :encrypted_street
|
36
|
+
t.binary :encrypted_street_iv
|
37
|
+
t.binary :encrypted_zipcode
|
38
|
+
t.string :mode
|
39
|
+
end
|
28
40
|
end
|
29
41
|
end
|
30
42
|
end
|
@@ -33,7 +45,6 @@ end
|
|
33
45
|
create_tables
|
34
46
|
|
35
47
|
ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
|
36
|
-
ActiveRecord::Base.logger = Logger.new(nil) if ::ActiveRecord::VERSION::STRING < "3.0"
|
37
48
|
|
38
49
|
if ::ActiveRecord::VERSION::STRING > "4.0"
|
39
50
|
module Rack
|
@@ -47,22 +58,17 @@ end
|
|
47
58
|
|
48
59
|
class Person < ActiveRecord::Base
|
49
60
|
self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
|
50
|
-
attr_encrypted :email, :
|
51
|
-
attr_encrypted :credentials, :
|
61
|
+
attr_encrypted :email, key: SECRET_KEY
|
62
|
+
attr_encrypted :credentials, key: Proc.new { |user| Encryptor.encrypt(value: user.salt, key: SECRET_KEY, iv: user.key_iv) }, marshal: true
|
52
63
|
|
53
|
-
|
54
|
-
def after_initialize
|
55
|
-
initialize_salt_and_credentials
|
56
|
-
end
|
57
|
-
else
|
58
|
-
after_initialize :initialize_salt_and_credentials
|
59
|
-
end
|
64
|
+
after_initialize :initialize_salt_and_credentials
|
60
65
|
|
61
66
|
protected
|
62
67
|
|
63
68
|
def initialize_salt_and_credentials
|
69
|
+
self.key_iv ||= SecureRandom.random_bytes(12)
|
64
70
|
self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(1000)).to_s)[0..15]
|
65
|
-
self.credentials ||= { :
|
71
|
+
self.credentials ||= { username: 'example', password: 'test' }
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
@@ -70,48 +76,64 @@ class PersonWithValidation < Person
|
|
70
76
|
validates_presence_of :email
|
71
77
|
end
|
72
78
|
|
79
|
+
class PersonWithProcMode < Person
|
80
|
+
attr_encrypted :email, key: SECRET_KEY, mode: Proc.new { :per_attribute_iv_and_salt }
|
81
|
+
attr_encrypted :credentials, key: SECRET_KEY, mode: Proc.new { :single_iv_and_salt }, insecure_mode: true
|
82
|
+
end
|
83
|
+
|
73
84
|
class Account < ActiveRecord::Base
|
74
85
|
attr_accessor :key
|
75
|
-
attr_encrypted :password, :
|
86
|
+
attr_encrypted :password, key: Proc.new {|account| account.key}
|
76
87
|
end
|
77
88
|
|
78
89
|
class PersonWithSerialization < ActiveRecord::Base
|
79
90
|
self.table_name = 'people'
|
80
|
-
attr_encrypted :email, :
|
91
|
+
attr_encrypted :email, key: SECRET_KEY
|
81
92
|
serialize :password
|
82
93
|
end
|
83
94
|
|
84
95
|
class UserWithProtectedAttribute < ActiveRecord::Base
|
85
96
|
self.table_name = 'users'
|
86
|
-
attr_encrypted :password, :
|
97
|
+
attr_encrypted :password, key: SECRET_KEY
|
87
98
|
attr_protected :is_admin if ::ActiveRecord::VERSION::STRING < "4.0"
|
88
99
|
end
|
89
100
|
|
90
101
|
class PersonUsingAlias < ActiveRecord::Base
|
91
102
|
self.table_name = 'people'
|
92
|
-
attr_encryptor :email, :
|
103
|
+
attr_encryptor :email, key: SECRET_KEY
|
93
104
|
end
|
94
105
|
|
95
|
-
class
|
106
|
+
class PrimeMinister < ActiveRecord::Base
|
107
|
+
attr_encrypted :name, marshal: true, key: SECRET_KEY
|
108
|
+
end
|
109
|
+
|
110
|
+
class Address < ActiveRecord::Base
|
111
|
+
self.attr_encrypted_options[:marshal] = false
|
112
|
+
self.attr_encrypted_options[:encode] = false
|
113
|
+
attr_encrypted :street, encode_iv: false, key: SECRET_KEY
|
114
|
+
attr_encrypted :zipcode, key: SECRET_KEY, mode: Proc.new { |address| address.mode.to_sym }, insecure_mode: true
|
115
|
+
end
|
116
|
+
|
117
|
+
class ActiveRecordTest < Minitest::Test
|
96
118
|
|
97
119
|
def setup
|
98
120
|
ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
|
99
121
|
create_tables
|
100
|
-
Account.create!(:
|
122
|
+
Account.create!(key: SECRET_KEY, password: "password")
|
101
123
|
end
|
102
124
|
|
103
125
|
def test_should_encrypt_email
|
104
|
-
@person = Person.create
|
105
|
-
|
106
|
-
|
107
|
-
assert_equal @person.email, Person.
|
126
|
+
@person = Person.create(email: 'test@example.com')
|
127
|
+
refute_nil @person.encrypted_email
|
128
|
+
refute_equal @person.email, @person.encrypted_email
|
129
|
+
assert_equal @person.email, Person.first.email
|
108
130
|
end
|
109
131
|
|
110
132
|
def test_should_marshal_and_encrypt_credentials
|
111
133
|
@person = Person.create
|
112
|
-
|
113
|
-
|
114
|
-
assert_equal @person.credentials, Person.
|
134
|
+
refute_nil @person.encrypted_credentials
|
135
|
+
refute_equal @person.credentials, @person.encrypted_credentials
|
136
|
+
assert_equal @person.credentials, Person.first.credentials
|
115
137
|
end
|
116
138
|
|
117
139
|
def test_should_encode_by_default
|
@@ -125,67 +147,103 @@ class ActiveRecordTest < Test::Unit::TestCase
|
|
125
147
|
end
|
126
148
|
|
127
149
|
def test_should_encrypt_decrypt_with_iv
|
128
|
-
@person = Person.create
|
150
|
+
@person = Person.create(email: 'test@example.com')
|
129
151
|
@person2 = Person.find(@person.id)
|
130
|
-
|
152
|
+
refute_nil @person2.encrypted_email_iv
|
131
153
|
assert_equal 'test@example.com', @person2.email
|
132
154
|
end
|
133
155
|
|
134
156
|
def test_should_ensure_attributes_can_be_deserialized
|
135
|
-
@person = PersonWithSerialization.new
|
157
|
+
@person = PersonWithSerialization.new(email: 'test@example.com', password: %w(an array of strings))
|
136
158
|
@person.save
|
137
159
|
assert_equal @person.password, %w(an array of strings)
|
138
160
|
end
|
139
161
|
|
140
162
|
def test_should_create_an_account_regardless_of_arguments_order
|
141
|
-
Account.create!(:
|
142
|
-
Account.create!(:
|
163
|
+
Account.create!(key: SECRET_KEY, password: "password")
|
164
|
+
Account.create!(password: "password" , key: SECRET_KEY)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_should_set_attributes_regardless_of_arguments_order
|
168
|
+
# minitest does not implement `assert_nothing_raised` https://github.com/seattlerb/minitest/issues/112
|
169
|
+
Account.new.attributes = { password: "password", key: SECRET_KEY }
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_should_preserve_hash_key_type
|
173
|
+
hash = { foo: 'bar' }
|
174
|
+
account = Account.create!(key: hash)
|
175
|
+
assert_equal account.key, hash
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_should_create_changed_predicate
|
179
|
+
person = Person.create!(email: 'test@example.com')
|
180
|
+
refute person.email_changed?
|
181
|
+
person.email = 'test@example.com'
|
182
|
+
refute person.email_changed?
|
183
|
+
person.email = nil
|
184
|
+
assert person.email_changed?
|
185
|
+
person.email = 'test2@example.com'
|
186
|
+
assert person.email_changed?
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_should_create_was_predicate
|
190
|
+
original_email = 'test@example.com'
|
191
|
+
person = Person.create!(email: original_email)
|
192
|
+
assert_equal original_email, person.email_was
|
193
|
+
person.email = 'test2@example.com'
|
194
|
+
assert_equal original_email, person.email_was
|
195
|
+
old_pm_name = "Winston Churchill"
|
196
|
+
pm = PrimeMinister.create!(name: old_pm_name)
|
197
|
+
assert_equal old_pm_name, pm.name_was
|
198
|
+
old_zipcode = "90210"
|
199
|
+
address = Address.create!(zipcode: old_zipcode, mode: "single_iv_and_salt")
|
200
|
+
assert_equal old_zipcode, address.zipcode_was
|
143
201
|
end
|
144
202
|
|
145
203
|
if ::ActiveRecord::VERSION::STRING > "4.0"
|
146
204
|
def test_should_assign_attributes
|
147
|
-
@user = UserWithProtectedAttribute.new
|
148
|
-
@user.attributes = ActionController::Parameters.new(:
|
205
|
+
@user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
|
206
|
+
@user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true).permit(:login)
|
149
207
|
assert_equal 'modified', @user.login
|
150
208
|
end
|
151
209
|
|
152
210
|
def test_should_not_assign_protected_attributes
|
153
|
-
@user = UserWithProtectedAttribute.new
|
154
|
-
@user.attributes = ActionController::Parameters.new(:
|
211
|
+
@user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
|
212
|
+
@user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true).permit(:login)
|
155
213
|
assert !@user.is_admin?
|
156
214
|
end
|
157
215
|
|
158
216
|
def test_should_raise_exception_if_not_permitted
|
159
|
-
@user = UserWithProtectedAttribute.new
|
160
|
-
|
161
|
-
@user.attributes = ActionController::Parameters.new(:
|
217
|
+
@user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
|
218
|
+
assert_raises ActiveModel::ForbiddenAttributesError do
|
219
|
+
@user.attributes = ActionController::Parameters.new(login: 'modified', is_admin: true)
|
162
220
|
end
|
163
221
|
end
|
164
222
|
|
165
223
|
def test_should_raise_exception_on_init_if_not_permitted
|
166
|
-
|
167
|
-
@user = UserWithProtectedAttribute.new ActionController::Parameters.new(:
|
224
|
+
assert_raises ActiveModel::ForbiddenAttributesError do
|
225
|
+
@user = UserWithProtectedAttribute.new ActionController::Parameters.new(login: 'modified', is_admin: true)
|
168
226
|
end
|
169
227
|
end
|
170
228
|
else
|
171
229
|
def test_should_assign_attributes
|
172
|
-
@user = UserWithProtectedAttribute.new
|
173
|
-
@user.attributes = {:
|
230
|
+
@user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
|
231
|
+
@user.attributes = { login: 'modified', is_admin: true }
|
174
232
|
assert_equal 'modified', @user.login
|
175
233
|
end
|
176
234
|
|
177
235
|
def test_should_not_assign_protected_attributes
|
178
|
-
@user = UserWithProtectedAttribute.new
|
179
|
-
@user.attributes = {:
|
236
|
+
@user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
|
237
|
+
@user.attributes = { login: 'modified', is_admin: true }
|
180
238
|
assert !@user.is_admin?
|
181
239
|
end
|
182
240
|
|
183
241
|
def test_should_assign_protected_attributes
|
184
|
-
@user = UserWithProtectedAttribute.new
|
242
|
+
@user = UserWithProtectedAttribute.new(login: 'login', is_admin: false)
|
185
243
|
if ::ActiveRecord::VERSION::STRING > "3.1"
|
186
|
-
@user.send
|
244
|
+
@user.send(:assign_attributes, { login: 'modified', is_admin: true }, without_protection: true)
|
187
245
|
else
|
188
|
-
@user.send
|
246
|
+
@user.send(:attributes=, { login: 'modified', is_admin: true }, false)
|
189
247
|
end
|
190
248
|
assert @user.is_admin?
|
191
249
|
end
|
@@ -196,6 +254,22 @@ class ActiveRecordTest < Test::Unit::TestCase
|
|
196
254
|
assert_nil(@person.attributes = nil)
|
197
255
|
end
|
198
256
|
|
257
|
+
def test_should_allow_proc_based_mode
|
258
|
+
@person = PersonWithProcMode.create(email: 'test@example.com', credentials: 'password123')
|
259
|
+
|
260
|
+
# Email is :per_attribute_iv_and_salt
|
261
|
+
assert_equal @person.class.encrypted_attributes[:email][:mode].class, Proc
|
262
|
+
assert_equal @person.class.encrypted_attributes[:email][:mode].call, :per_attribute_iv_and_salt
|
263
|
+
refute_nil @person.encrypted_email_salt
|
264
|
+
refute_nil @person.encrypted_email_iv
|
265
|
+
|
266
|
+
# Credentials is :single_iv_and_salt
|
267
|
+
assert_equal @person.class.encrypted_attributes[:credentials][:mode].class, Proc
|
268
|
+
assert_equal @person.class.encrypted_attributes[:credentials][:mode].call, :single_iv_and_salt
|
269
|
+
assert_nil @person.encrypted_credentials_salt
|
270
|
+
assert_nil @person.encrypted_credentials_iv
|
271
|
+
end
|
272
|
+
|
199
273
|
if ::ActiveRecord::VERSION::STRING > "3.1"
|
200
274
|
def test_should_allow_assign_attributes_with_nil
|
201
275
|
@person = Person.new
|
@@ -203,15 +277,41 @@ class ActiveRecordTest < Test::Unit::TestCase
|
|
203
277
|
end
|
204
278
|
end
|
205
279
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
user.save
|
280
|
+
def test_that_alias_encrypts_column
|
281
|
+
user = PersonUsingAlias.new
|
282
|
+
user.email = 'test@example.com'
|
283
|
+
user.save
|
211
284
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
285
|
+
refute_nil user.encrypted_email
|
286
|
+
refute_equal user.email, user.encrypted_email
|
287
|
+
assert_equal user.email, PersonUsingAlias.first.email
|
288
|
+
end
|
289
|
+
|
290
|
+
# See https://github.com/attr-encrypted/attr_encrypted/issues/68
|
291
|
+
def test_should_invalidate_virtual_attributes_on_reload
|
292
|
+
old_pm_name = 'Winston Churchill'
|
293
|
+
new_pm_name = 'Neville Chamberlain'
|
294
|
+
pm = PrimeMinister.create!(name: old_pm_name)
|
295
|
+
assert_equal old_pm_name, pm.name
|
296
|
+
pm.name = new_pm_name
|
297
|
+
assert_equal new_pm_name, pm.name
|
298
|
+
|
299
|
+
result = pm.reload
|
300
|
+
assert_equal pm, result
|
301
|
+
assert_equal old_pm_name, pm.name
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_should_save_encrypted_data_as_binary
|
305
|
+
street = '123 Elm'
|
306
|
+
address = Address.create!(street: street)
|
307
|
+
refute_equal address.encrypted_street, street
|
308
|
+
assert_equal Address.first.street, street
|
309
|
+
end
|
310
|
+
|
311
|
+
def test_should_evaluate_proc_based_mode
|
312
|
+
street = '123 Elm'
|
313
|
+
zipcode = '12345'
|
314
|
+
address = Address.new(street: street, zipcode: zipcode, mode: :single_iv_and_salt)
|
315
|
+
assert_nil address.encrypted_zipcode_iv
|
216
316
|
end
|
217
317
|
end
|