symmetric-encryption 3.4.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +102 -55
- data/Rakefile +13 -8
- data/lib/rails/generators/symmetric_encryption/config/config_generator.rb +1 -1
- data/lib/rails/generators/symmetric_encryption/heroku_config/templates/symmetric-encryption.yml +2 -2
- data/lib/rails/generators/symmetric_encryption/new_keys/new_keys_generator.rb +2 -2
- data/lib/symmetric_encryption.rb +7 -6
- data/lib/symmetric_encryption/cipher.rb +4 -4
- data/lib/symmetric_encryption/extensions/active_record/base.rb +6 -46
- data/lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb +129 -0
- data/lib/symmetric_encryption/{mongoid.rb → extensions/mongoid/encrypted.rb} +12 -46
- data/lib/symmetric_encryption/generator.rb +54 -0
- data/lib/symmetric_encryption/railtie.rb +3 -3
- data/lib/symmetric_encryption/railties/symmetric_encryption.rake +1 -1
- data/lib/symmetric_encryption/railties/symmetric_encryption_validator.rb +1 -1
- data/lib/symmetric_encryption/reader.rb +3 -3
- data/lib/symmetric_encryption/symmetric_encryption.rb +25 -15
- data/lib/symmetric_encryption/version.rb +1 -1
- data/lib/symmetric_encryption/writer.rb +4 -4
- data/test/active_record_test.rb +474 -0
- data/test/cipher_test.rb +15 -15
- data/test/config/mongo_mapper.yml +7 -0
- data/test/{field_encrypted_test.rb → mongo_mapper_test.rb} +68 -67
- data/test/mongoid_test.rb +535 -0
- data/test/reader_test.rb +10 -10
- data/test/symmetric_encryption_test.rb +27 -27
- data/test/test_db.sqlite3 +0 -0
- data/test/test_helper.rb +0 -1
- data/test/writer_test.rb +2 -2
- metadata +14 -8
- data/test/attr_encrypted_test.rb +0 -622
data/test/reader_test.rb
CHANGED
@@ -89,19 +89,19 @@ class ReaderTest < Test::Unit::TestCase
|
|
89
89
|
|
90
90
|
[
|
91
91
|
# No Header
|
92
|
-
{:
|
92
|
+
{header: false, random_key: false, random_iv: false},
|
93
93
|
# Default Header with random key and iv
|
94
94
|
{},
|
95
95
|
# Header with no compression ( default anyway )
|
96
|
-
{:
|
96
|
+
{compress: false},
|
97
97
|
# Compress and use Random key, iv
|
98
|
-
{:
|
98
|
+
{compress: true},
|
99
99
|
# Header but not random key or iv
|
100
|
-
{:
|
100
|
+
{random_key: false},
|
101
101
|
# Random iv only
|
102
|
-
{:
|
102
|
+
{random_key: false, random_iv: true},
|
103
103
|
# Random iv only with compression
|
104
|
-
{:
|
104
|
+
{random_iv: true, compress: true},
|
105
105
|
].each do |options|
|
106
106
|
|
107
107
|
[:data, :empty, :blank].each do |usecase|
|
@@ -245,7 +245,7 @@ class ReaderTest < Test::Unit::TestCase
|
|
245
245
|
setup do
|
246
246
|
@filename = '_test'
|
247
247
|
# Create encrypted file with old encryption key
|
248
|
-
SymmetricEncryption::Writer.open(@filename, :
|
248
|
+
SymmetricEncryption::Writer.open(@filename, version: 0) do |file|
|
249
249
|
@data.inject(0) {|sum,str| sum + file.write(str)}
|
250
250
|
end
|
251
251
|
end
|
@@ -283,7 +283,7 @@ class ReaderTest < Test::Unit::TestCase
|
|
283
283
|
setup do
|
284
284
|
@filename = '_test'
|
285
285
|
# Create encrypted file with old encryption key
|
286
|
-
SymmetricEncryption::Writer.open(@filename, :
|
286
|
+
SymmetricEncryption::Writer.open(@filename, version: 0, header: false, random_key: false) do |file|
|
287
287
|
@data.inject(0) {|sum,str| sum + file.write(str)}
|
288
288
|
end
|
289
289
|
end
|
@@ -297,14 +297,14 @@ class ReaderTest < Test::Unit::TestCase
|
|
297
297
|
end
|
298
298
|
|
299
299
|
should "decrypt from file in a single read" do
|
300
|
-
decrypted = SymmetricEncryption::Reader.open(@filename, :
|
300
|
+
decrypted = SymmetricEncryption::Reader.open(@filename, version: 0) {|file| file.read}
|
301
301
|
assert_equal @data_str, decrypted
|
302
302
|
end
|
303
303
|
|
304
304
|
should "decrypt from file in a single read with different version" do
|
305
305
|
# Should fail since file was encrypted using version 0 key
|
306
306
|
assert_raise OpenSSL::Cipher::CipherError do
|
307
|
-
SymmetricEncryption::Reader.open(@filename, :
|
307
|
+
SymmetricEncryption::Reader.open(@filename, version: 2) {|file| file.read}
|
308
308
|
end
|
309
309
|
end
|
310
310
|
end
|
@@ -108,41 +108,41 @@ class SymmetricEncryptionTest < Test::Unit::TestCase
|
|
108
108
|
assert_equal false, SymmetricEncryption.encrypted?(@social_security_number)
|
109
109
|
end
|
110
110
|
end
|
111
|
+
end
|
111
112
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
113
|
+
context "using select_cipher" do
|
114
|
+
setup do
|
115
|
+
@social_security_number = "987654321"
|
116
|
+
# Encrypt data without a header and encode with base64 which has a trailing '\n'
|
117
|
+
@encrypted_0_ssn = SymmetricEncryption.cipher(0).encode(SymmetricEncryption.cipher(0).binary_encrypt(@social_security_number,false,false,false))
|
117
118
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
119
|
+
SymmetricEncryption.select_cipher do |encoded_str, decoded_str|
|
120
|
+
# Use cipher version 0 if the encoded string ends with "\n" otherwise
|
121
|
+
# use the current default cipher
|
122
|
+
encoded_str.end_with?("\n") ? SymmetricEncryption.cipher(0) : SymmetricEncryption.cipher
|
123
123
|
end
|
124
|
+
end
|
124
125
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
teardown do
|
127
|
+
# Clear out select_cipher
|
128
|
+
SymmetricEncryption.select_cipher
|
129
|
+
end
|
129
130
|
|
130
|
-
|
131
|
-
|
132
|
-
end
|
131
|
+
should "decrypt string without a header using an old cipher" do
|
132
|
+
assert_equal @social_security_number, SymmetricEncryption.decrypt(@encrypted_0_ssn)
|
133
133
|
end
|
134
|
+
end
|
134
135
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
136
|
+
context "without select_cipher" do
|
137
|
+
setup do
|
138
|
+
@social_security_number = "987654321"
|
139
|
+
# Encrypt data without a header and encode with base64 which has a trailing '\n'
|
140
|
+
assert @encrypted_0_ssn = SymmetricEncryption.cipher(0).encode(SymmetricEncryption.cipher(0).binary_encrypt(@social_security_number,false,false,false))
|
141
|
+
end
|
141
142
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
end
|
143
|
+
should "decrypt string without a header using an old cipher" do
|
144
|
+
assert_raises OpenSSL::Cipher::CipherError do
|
145
|
+
SymmetricEncryption.decrypt(@encrypted_0_ssn)
|
146
146
|
end
|
147
147
|
end
|
148
148
|
end
|
data/test/test_db.sqlite3
CHANGED
Binary file
|
data/test/test_helper.rb
CHANGED
@@ -7,7 +7,6 @@ require 'erb'
|
|
7
7
|
require 'test/unit'
|
8
8
|
# Since we want both the AR and Mongoid extensions loaded we need to require them first
|
9
9
|
require 'active_record'
|
10
|
-
require 'mongoid'
|
11
10
|
require 'symmetric-encryption'
|
12
11
|
# Should redefines Proc#bind so must include after Rails
|
13
12
|
require 'shoulda'
|
data/test/writer_test.rb
CHANGED
@@ -27,7 +27,7 @@ class WriterTest < Test::Unit::TestCase
|
|
27
27
|
|
28
28
|
should "encrypt to string stream" do
|
29
29
|
stream = StringIO.new
|
30
|
-
file = SymmetricEncryption::Writer.new(stream, :
|
30
|
+
file = SymmetricEncryption::Writer.new(stream, header: false, random_key: false, random_iv: false)
|
31
31
|
written_len = @data.inject(0) {|sum,str| sum + file.write(str)}
|
32
32
|
assert_equal @data_len, file.size
|
33
33
|
file.close
|
@@ -50,7 +50,7 @@ class WriterTest < Test::Unit::TestCase
|
|
50
50
|
|
51
51
|
should "encrypt to file using .open" do
|
52
52
|
written_len = nil
|
53
|
-
SymmetricEncryption::Writer.open(@filename, :
|
53
|
+
SymmetricEncryption::Writer.open(@filename, header: false, random_key: false, random_iv: false) do |file|
|
54
54
|
written_len = @data.inject(0) {|sum,str| sum + file.write(str)}
|
55
55
|
assert_equal @data_len, file.size
|
56
56
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: symmetric-encryption
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coercible
|
@@ -46,7 +46,9 @@ files:
|
|
46
46
|
- lib/symmetric_encryption.rb
|
47
47
|
- lib/symmetric_encryption/cipher.rb
|
48
48
|
- lib/symmetric_encryption/extensions/active_record/base.rb
|
49
|
-
- lib/symmetric_encryption/
|
49
|
+
- lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb
|
50
|
+
- lib/symmetric_encryption/extensions/mongoid/encrypted.rb
|
51
|
+
- lib/symmetric_encryption/generator.rb
|
50
52
|
- lib/symmetric_encryption/railtie.rb
|
51
53
|
- lib/symmetric_encryption/railties/symmetric_encryption.rake
|
52
54
|
- lib/symmetric_encryption/railties/symmetric_encryption_validator.rb
|
@@ -54,10 +56,11 @@ files:
|
|
54
56
|
- lib/symmetric_encryption/symmetric_encryption.rb
|
55
57
|
- lib/symmetric_encryption/version.rb
|
56
58
|
- lib/symmetric_encryption/writer.rb
|
57
|
-
- test/
|
59
|
+
- test/active_record_test.rb
|
58
60
|
- test/cipher_test.rb
|
59
61
|
- test/config/database.yml
|
60
62
|
- test/config/empty.csv
|
63
|
+
- test/config/mongo_mapper.yml
|
61
64
|
- test/config/mongoid_v2.yml
|
62
65
|
- test/config/mongoid_v3.yml
|
63
66
|
- test/config/symmetric-encryption.yml
|
@@ -65,7 +68,8 @@ files:
|
|
65
68
|
- test/config/test_new.key
|
66
69
|
- test/config/test_secondary_1.iv
|
67
70
|
- test/config/test_secondary_1.key
|
68
|
-
- test/
|
71
|
+
- test/mongo_mapper_test.rb
|
72
|
+
- test/mongoid_test.rb
|
69
73
|
- test/reader_test.rb
|
70
74
|
- test/symmetric_encryption_test.rb
|
71
75
|
- test/test_db.sqlite3
|
@@ -91,15 +95,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
95
|
version: '0'
|
92
96
|
requirements: []
|
93
97
|
rubyforge_project:
|
94
|
-
rubygems_version: 2.2.
|
98
|
+
rubygems_version: 2.2.2
|
95
99
|
signing_key:
|
96
100
|
specification_version: 4
|
97
101
|
summary: Symmetric Encryption for Ruby, and Ruby on Rails
|
98
102
|
test_files:
|
99
|
-
- test/
|
103
|
+
- test/active_record_test.rb
|
100
104
|
- test/cipher_test.rb
|
101
105
|
- test/config/database.yml
|
102
106
|
- test/config/empty.csv
|
107
|
+
- test/config/mongo_mapper.yml
|
103
108
|
- test/config/mongoid_v2.yml
|
104
109
|
- test/config/mongoid_v3.yml
|
105
110
|
- test/config/symmetric-encryption.yml
|
@@ -107,7 +112,8 @@ test_files:
|
|
107
112
|
- test/config/test_new.key
|
108
113
|
- test/config/test_secondary_1.iv
|
109
114
|
- test/config/test_secondary_1.key
|
110
|
-
- test/
|
115
|
+
- test/mongo_mapper_test.rb
|
116
|
+
- test/mongoid_test.rb
|
111
117
|
- test/reader_test.rb
|
112
118
|
- test/symmetric_encryption_test.rb
|
113
119
|
- test/test_db.sqlite3
|
data/test/attr_encrypted_test.rb
DELETED
@@ -1,622 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/test_helper'
|
2
|
-
|
3
|
-
ActiveRecord::Base.logger = SemanticLogger[ActiveRecord]
|
4
|
-
ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read('test/config/database.yml')).result)
|
5
|
-
ActiveRecord::Base.establish_connection('test')
|
6
|
-
|
7
|
-
ActiveRecord::Schema.define :version => 0 do
|
8
|
-
create_table :users, :force => true do |t|
|
9
|
-
t.string :encrypted_bank_account_number
|
10
|
-
t.string :encrypted_social_security_number
|
11
|
-
t.string :encrypted_string
|
12
|
-
t.text :encrypted_long_string
|
13
|
-
t.text :encrypted_data_yaml
|
14
|
-
t.text :encrypted_data_json
|
15
|
-
t.string :name
|
16
|
-
|
17
|
-
t.string :encrypted_integer_value
|
18
|
-
t.string :encrypted_float_value
|
19
|
-
t.string :encrypted_decimal_value
|
20
|
-
t.string :encrypted_datetime_value
|
21
|
-
t.string :encrypted_time_value
|
22
|
-
t.string :encrypted_date_value
|
23
|
-
t.string :encrypted_true_value
|
24
|
-
t.string :encrypted_false_value
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class User < ActiveRecord::Base
|
29
|
-
attr_encrypted :bank_account_number
|
30
|
-
attr_encrypted :social_security_number
|
31
|
-
attr_encrypted :string, :random_iv => true
|
32
|
-
attr_encrypted :long_string, :random_iv => true, :compress => true
|
33
|
-
attr_encrypted :data_yaml, :random_iv => true, :compress => true, :type => :yaml
|
34
|
-
attr_encrypted :data_json, :random_iv => true, :compress => true, :type => :json
|
35
|
-
|
36
|
-
attr_encrypted :integer_value, :type => :integer
|
37
|
-
attr_encrypted :float_value, :type => :float
|
38
|
-
attr_encrypted :decimal_value, :type => :decimal
|
39
|
-
attr_encrypted :datetime_value, :type => :datetime
|
40
|
-
attr_encrypted :time_value, :type => :time
|
41
|
-
attr_encrypted :date_value, :type => :date
|
42
|
-
attr_encrypted :true_value, :type => :boolean
|
43
|
-
attr_encrypted :false_value, :type => :boolean
|
44
|
-
|
45
|
-
validates :encrypted_bank_account_number, :symmetric_encryption => true
|
46
|
-
validates :encrypted_social_security_number, :symmetric_encryption => true
|
47
|
-
end
|
48
|
-
|
49
|
-
# Load Symmetric Encryption keys
|
50
|
-
SymmetricEncryption.load!(File.join(File.dirname(__FILE__), 'config', 'symmetric-encryption.yml'), 'test')
|
51
|
-
|
52
|
-
# Initialize the database connection
|
53
|
-
config_file = File.join(File.dirname(__FILE__), 'config', 'database.yml')
|
54
|
-
raise "database config not found. Create a config file at: test/config/database.yml" unless File.exists? config_file
|
55
|
-
|
56
|
-
cfg = YAML.load(ERB.new(File.new(config_file).read).result)['test']
|
57
|
-
raise("Environment 'test' not defined in test/config/database.yml") unless cfg
|
58
|
-
|
59
|
-
User.establish_connection(cfg)
|
60
|
-
|
61
|
-
#
|
62
|
-
# Unit Test for attr_encrypted and validation aspects of SymmetricEncryption
|
63
|
-
#
|
64
|
-
class AttrEncryptedTest < Test::Unit::TestCase
|
65
|
-
context 'the SymmetricEncryption Library' do
|
66
|
-
|
67
|
-
setup do
|
68
|
-
@bank_account_number = "1234567890"
|
69
|
-
@bank_account_number_encrypted = "QEVuQwIAL94ArJeFlJrZp6SYsvoOGA=="
|
70
|
-
|
71
|
-
@social_security_number = "987654321"
|
72
|
-
@social_security_number_encrypted = "QEVuQwIAS+8X1NRrqdfEIQyFHVPuVA=="
|
73
|
-
|
74
|
-
@string = "A string containing some data to be encrypted with a random initialization vector"
|
75
|
-
@long_string = "A string containing some data to be encrypted with a random initialization vector and compressed since it takes up so much space in plain text form"
|
76
|
-
|
77
|
-
@name = 'Joe Bloggs'
|
78
|
-
|
79
|
-
@integer_value = 12
|
80
|
-
@float_value = 88.12345
|
81
|
-
@decimal_value = BigDecimal.new("22.51")
|
82
|
-
@datetime_value = DateTime.new(2001, 11, 26, 20, 55, 54, "-5")
|
83
|
-
@time_value = Time.new(2013, 01, 01, 22, 30, 00, "-04:00")
|
84
|
-
@date_value = Date.new(1927, 04, 02)
|
85
|
-
@h = { :a => 'A', :b => 'B' }
|
86
|
-
|
87
|
-
@user = User.new(
|
88
|
-
# Encrypted Attribute
|
89
|
-
:bank_account_number => @bank_account_number,
|
90
|
-
# Encrypted Attribute
|
91
|
-
:social_security_number => @social_security_number,
|
92
|
-
:name => @name,
|
93
|
-
# data type specific fields
|
94
|
-
:integer_value => @integer_value,
|
95
|
-
:float_value => @float_value,
|
96
|
-
:decimal_value => @decimal_value,
|
97
|
-
:datetime_value => @datetime_value,
|
98
|
-
:time_value => @time_value,
|
99
|
-
:date_value => @date_value,
|
100
|
-
:true_value => true,
|
101
|
-
:false_value => false,
|
102
|
-
:data_yaml => @h.dup,
|
103
|
-
:data_json => @h.dup
|
104
|
-
)
|
105
|
-
end
|
106
|
-
|
107
|
-
should "have encrypted methods" do
|
108
|
-
assert_equal true, @user.respond_to?(:encrypted_bank_account_number)
|
109
|
-
assert_equal true, @user.respond_to?(:bank_account_number)
|
110
|
-
assert_equal true, @user.respond_to?(:encrypted_social_security_number)
|
111
|
-
assert_equal true, @user.respond_to?(:social_security_number)
|
112
|
-
assert_equal true, @user.respond_to?(:data_yaml)
|
113
|
-
assert_equal true, @user.respond_to?(:data_json)
|
114
|
-
assert_equal false, @user.respond_to?(:encrypted_name)
|
115
|
-
end
|
116
|
-
|
117
|
-
should "have unencrypted values" do
|
118
|
-
assert_equal @bank_account_number, @user.bank_account_number
|
119
|
-
assert_equal @social_security_number, @user.social_security_number
|
120
|
-
end
|
121
|
-
|
122
|
-
should "have encrypted values" do
|
123
|
-
assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
|
124
|
-
assert_equal @social_security_number_encrypted, @user.encrypted_social_security_number
|
125
|
-
end
|
126
|
-
|
127
|
-
should "support same iv" do
|
128
|
-
@user.social_security_number = @social_security_number
|
129
|
-
assert first_value = @user.social_security_number
|
130
|
-
# Assign the same value
|
131
|
-
@user.social_security_number = @social_security_number
|
132
|
-
assert_equal first_value, @user.social_security_number
|
133
|
-
end
|
134
|
-
|
135
|
-
should "support a random iv" do
|
136
|
-
@user.string = @string
|
137
|
-
assert first_value = @user.encrypted_string
|
138
|
-
# Assign the same value
|
139
|
-
@user.string = @string.dup
|
140
|
-
assert_equal true, first_value != @user.encrypted_string
|
141
|
-
end
|
142
|
-
|
143
|
-
should "support a random iv and compress" do
|
144
|
-
@user.string = @long_string
|
145
|
-
@user.long_string = @long_string
|
146
|
-
|
147
|
-
assert_equal true, (@user.encrypted_long_string.length.to_f / @user.encrypted_string.length) < 0.8
|
148
|
-
end
|
149
|
-
|
150
|
-
should "encrypt" do
|
151
|
-
user = User.new
|
152
|
-
user.bank_account_number = @bank_account_number
|
153
|
-
assert_equal @bank_account_number, user.bank_account_number
|
154
|
-
assert_equal @bank_account_number_encrypted, user.encrypted_bank_account_number
|
155
|
-
end
|
156
|
-
|
157
|
-
should "allow lookups using unencrypted or encrypted column name" do
|
158
|
-
@user.save!
|
159
|
-
|
160
|
-
inq = User.find_by_bank_account_number(@bank_account_number)
|
161
|
-
assert_equal @bank_account_number, inq.bank_account_number
|
162
|
-
assert_equal @bank_account_number_encrypted, inq.encrypted_bank_account_number
|
163
|
-
|
164
|
-
@user.delete
|
165
|
-
end
|
166
|
-
|
167
|
-
should "all paths should lead to the same result" do
|
168
|
-
assert_equal @bank_account_number_encrypted, (@user.encrypted_social_security_number = @bank_account_number_encrypted)
|
169
|
-
assert_equal @bank_account_number, @user.social_security_number
|
170
|
-
assert_equal @bank_account_number_encrypted, @user.encrypted_social_security_number
|
171
|
-
end
|
172
|
-
|
173
|
-
should "all paths should lead to the same result 2" do
|
174
|
-
assert_equal @bank_account_number, (@user.social_security_number = @bank_account_number)
|
175
|
-
assert_equal @bank_account_number_encrypted, @user.encrypted_social_security_number
|
176
|
-
assert_equal @bank_account_number, @user.social_security_number
|
177
|
-
end
|
178
|
-
|
179
|
-
should "all paths should lead to the same result, check uninitialized" do
|
180
|
-
user = User.new
|
181
|
-
assert_equal nil, user.social_security_number
|
182
|
-
assert_equal @bank_account_number, (user.social_security_number = @bank_account_number)
|
183
|
-
assert_equal @bank_account_number, user.social_security_number
|
184
|
-
assert_equal @bank_account_number_encrypted, user.encrypted_social_security_number
|
185
|
-
|
186
|
-
assert_equal nil, (user.social_security_number = nil)
|
187
|
-
assert_equal nil, user.social_security_number
|
188
|
-
assert_equal nil, user.encrypted_social_security_number
|
189
|
-
end
|
190
|
-
|
191
|
-
should "allow unencrypted values to be passed to the constructor" do
|
192
|
-
user = User.new(:bank_account_number => @bank_account_number, :social_security_number => @social_security_number)
|
193
|
-
assert_equal @bank_account_number, user.bank_account_number
|
194
|
-
assert_equal @social_security_number, user.social_security_number
|
195
|
-
assert_equal @bank_account_number_encrypted, user.encrypted_bank_account_number
|
196
|
-
assert_equal @social_security_number_encrypted, user.encrypted_social_security_number
|
197
|
-
end
|
198
|
-
|
199
|
-
should "return encrypted attributes for the class" do
|
200
|
-
expect = {:social_security_number=>:encrypted_social_security_number, :bank_account_number=>:encrypted_bank_account_number}
|
201
|
-
result = User.encrypted_attributes
|
202
|
-
expect.each_pair {|k,v| assert_equal expect[k], result[k]}
|
203
|
-
end
|
204
|
-
|
205
|
-
should "return encrypted keys for the class" do
|
206
|
-
expect = [:social_security_number, :bank_account_number]
|
207
|
-
result = User.encrypted_keys
|
208
|
-
expect.each {|val| assert_equal true, result.include?(val)}
|
209
|
-
|
210
|
-
# Also check encrypted_attribute?
|
211
|
-
expect.each {|val| assert_equal true, User.encrypted_attribute?(val)}
|
212
|
-
end
|
213
|
-
|
214
|
-
should "return encrypted columns for the class" do
|
215
|
-
expect = [:encrypted_social_security_number, :encrypted_bank_account_number]
|
216
|
-
result = User.encrypted_columns
|
217
|
-
expect.each {|val| assert_equal true, result.include?(val)}
|
218
|
-
|
219
|
-
# Also check encrypted_column?
|
220
|
-
expect.each {|val| assert_equal true, User.encrypted_column?(val)}
|
221
|
-
end
|
222
|
-
|
223
|
-
should "validate encrypted data" do
|
224
|
-
assert_equal true, @user.valid?
|
225
|
-
@user.encrypted_bank_account_number = '123'
|
226
|
-
assert_equal false, @user.valid?
|
227
|
-
assert_equal ["must be a value encrypted using SymmetricEncryption.encrypt"], @user.errors[:encrypted_bank_account_number]
|
228
|
-
@user.encrypted_bank_account_number = SymmetricEncryption.encrypt('123')
|
229
|
-
assert_equal true, @user.valid?
|
230
|
-
@user.bank_account_number = '123'
|
231
|
-
assert_equal true, @user.valid?
|
232
|
-
end
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
context "with saved user" do
|
237
|
-
setup do
|
238
|
-
@user.save!
|
239
|
-
end
|
240
|
-
|
241
|
-
teardown do
|
242
|
-
@user.destroy
|
243
|
-
end
|
244
|
-
|
245
|
-
should "return correct data type before save" do
|
246
|
-
u = User.new(:integer_value => "5")
|
247
|
-
assert_equal 5, u.integer_value
|
248
|
-
assert u.integer_value.kind_of?(Integer)
|
249
|
-
end
|
250
|
-
|
251
|
-
should "handle gsub! for non-encrypted_field" do
|
252
|
-
@user.name.gsub!('a', 'v')
|
253
|
-
new_name = @name.gsub('a', 'v')
|
254
|
-
assert_equal new_name, @user.name
|
255
|
-
@user.reload
|
256
|
-
assert_equal new_name, @user.name
|
257
|
-
end
|
258
|
-
|
259
|
-
should "prevent gsub! on non-encrypted value of encrypted_field" do
|
260
|
-
# can't modify frozen String
|
261
|
-
assert_raises RuntimeError do
|
262
|
-
@user.bank_account_number.gsub!('5', '4')
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
should "revert changes on reload" do
|
267
|
-
new_bank_account_number = '444444444'
|
268
|
-
@user.bank_account_number = new_bank_account_number
|
269
|
-
assert_equal new_bank_account_number, @user.bank_account_number
|
270
|
-
|
271
|
-
# Reload User model from the database
|
272
|
-
@user.reload
|
273
|
-
assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
|
274
|
-
assert_equal @bank_account_number, @user.bank_account_number
|
275
|
-
end
|
276
|
-
|
277
|
-
should "revert changes to encrypted field on reload" do
|
278
|
-
new_bank_account_number = '111111111'
|
279
|
-
new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
|
280
|
-
@user.encrypted_bank_account_number = new_encrypted_bank_account_number
|
281
|
-
assert_equal new_encrypted_bank_account_number, @user.encrypted_bank_account_number
|
282
|
-
assert_equal new_bank_account_number, @user.bank_account_number
|
283
|
-
|
284
|
-
# Reload User model from the database
|
285
|
-
@user.reload
|
286
|
-
assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
|
287
|
-
assert_equal @bank_account_number, @user.bank_account_number
|
288
|
-
end
|
289
|
-
|
290
|
-
context "data types" do
|
291
|
-
setup do
|
292
|
-
@user_clone = User.find(@user.id)
|
293
|
-
end
|
294
|
-
|
295
|
-
context "integer values" do
|
296
|
-
should "return correct data type" do
|
297
|
-
assert_equal @integer_value, @user_clone.integer_value
|
298
|
-
assert @user.clone.integer_value.kind_of?(Integer)
|
299
|
-
end
|
300
|
-
|
301
|
-
should "coerce data type before save" do
|
302
|
-
u = User.new(:integer_value => "5")
|
303
|
-
assert_equal 5, u.integer_value
|
304
|
-
assert u.integer_value.kind_of?(Integer)
|
305
|
-
end
|
306
|
-
|
307
|
-
should "permit replacing value with nil" do
|
308
|
-
@user_clone.integer_value = nil
|
309
|
-
@user_clone.save!
|
310
|
-
|
311
|
-
@user.reload
|
312
|
-
assert_nil @user.integer_value
|
313
|
-
assert_nil @user.encrypted_integer_value
|
314
|
-
end
|
315
|
-
|
316
|
-
should "permit replacing value" do
|
317
|
-
new_integer_value = 98
|
318
|
-
@user_clone.integer_value = new_integer_value
|
319
|
-
@user_clone.save!
|
320
|
-
|
321
|
-
@user.reload
|
322
|
-
assert_equal new_integer_value, @user.integer_value
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
context "float values" do
|
327
|
-
should "return correct data type" do
|
328
|
-
assert_equal @float_value, @user_clone.float_value
|
329
|
-
assert @user.clone.float_value.kind_of?(Float)
|
330
|
-
end
|
331
|
-
|
332
|
-
should "coerce data type before save" do
|
333
|
-
u = User.new(:float_value => "5.6")
|
334
|
-
assert_equal 5.6, u.float_value
|
335
|
-
assert u.float_value.kind_of?(Float)
|
336
|
-
end
|
337
|
-
|
338
|
-
should "permit replacing value with nil" do
|
339
|
-
@user_clone.float_value = nil
|
340
|
-
@user_clone.save!
|
341
|
-
|
342
|
-
@user.reload
|
343
|
-
assert_nil @user.float_value
|
344
|
-
assert_nil @user.encrypted_float_value
|
345
|
-
end
|
346
|
-
|
347
|
-
should "permit replacing value" do
|
348
|
-
new_float_value = 45.4321
|
349
|
-
@user_clone.float_value = new_float_value
|
350
|
-
@user_clone.save!
|
351
|
-
|
352
|
-
@user.reload
|
353
|
-
assert_equal new_float_value, @user.float_value
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
context "decimal values" do
|
358
|
-
should "return correct data type" do
|
359
|
-
assert_equal @decimal_value, @user_clone.decimal_value
|
360
|
-
assert @user.clone.decimal_value.kind_of?(BigDecimal)
|
361
|
-
end
|
362
|
-
|
363
|
-
should "coerce data type before save" do
|
364
|
-
u = User.new(:decimal_value => "99.95")
|
365
|
-
assert_equal BigDecimal.new("99.95"), u.decimal_value
|
366
|
-
assert u.decimal_value.kind_of?(BigDecimal)
|
367
|
-
end
|
368
|
-
|
369
|
-
should "permit replacing value with nil" do
|
370
|
-
@user_clone.decimal_value = nil
|
371
|
-
@user_clone.save!
|
372
|
-
|
373
|
-
@user.reload
|
374
|
-
assert_nil @user.decimal_value
|
375
|
-
assert_nil @user.encrypted_decimal_value
|
376
|
-
end
|
377
|
-
|
378
|
-
should "permit replacing value" do
|
379
|
-
new_decimal_value = BigDecimal.new("99.95")
|
380
|
-
@user_clone.decimal_value = new_decimal_value
|
381
|
-
@user_clone.save!
|
382
|
-
|
383
|
-
@user.reload
|
384
|
-
assert_equal new_decimal_value, @user.decimal_value
|
385
|
-
end
|
386
|
-
end
|
387
|
-
|
388
|
-
context "datetime values" do
|
389
|
-
should "return correct data type" do
|
390
|
-
assert_equal @datetime_value, @user_clone.datetime_value
|
391
|
-
assert @user.clone.datetime_value.kind_of?(DateTime)
|
392
|
-
end
|
393
|
-
|
394
|
-
should "coerce data type before save" do
|
395
|
-
now = Time.now
|
396
|
-
u = User.new(:datetime_value => now)
|
397
|
-
assert_equal now, u.datetime_value
|
398
|
-
assert u.datetime_value.kind_of?(DateTime)
|
399
|
-
end
|
400
|
-
|
401
|
-
should "permit replacing value with nil" do
|
402
|
-
@user_clone.datetime_value = nil
|
403
|
-
@user_clone.save!
|
404
|
-
|
405
|
-
@user.reload
|
406
|
-
assert_nil @user.datetime_value
|
407
|
-
assert_nil @user.encrypted_datetime_value
|
408
|
-
end
|
409
|
-
|
410
|
-
should "permit replacing value" do
|
411
|
-
new_datetime_value = DateTime.new(1998, 10, 21, 8, 33, 28, "+5")
|
412
|
-
@user_clone.datetime_value = new_datetime_value
|
413
|
-
@user_clone.save!
|
414
|
-
|
415
|
-
@user.reload
|
416
|
-
assert_equal new_datetime_value, @user.datetime_value
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
context "time values" do
|
421
|
-
should "return correct data type" do
|
422
|
-
assert_equal @time_value, @user_clone.time_value
|
423
|
-
assert @user.clone.time_value.kind_of?(Time)
|
424
|
-
end
|
425
|
-
|
426
|
-
should "coerce data type before save" do
|
427
|
-
now = Time.now
|
428
|
-
u = User.new(:time_value => now)
|
429
|
-
assert_equal now, u.time_value
|
430
|
-
assert u.time_value.kind_of?(Time)
|
431
|
-
end
|
432
|
-
|
433
|
-
should "permit replacing value with nil" do
|
434
|
-
@user_clone.time_value = nil
|
435
|
-
@user_clone.save!
|
436
|
-
|
437
|
-
@user.reload
|
438
|
-
assert_nil @user.time_value
|
439
|
-
assert_nil @user.encrypted_time_value
|
440
|
-
end
|
441
|
-
|
442
|
-
should "permit replacing value" do
|
443
|
-
new_time_value = Time.new(1998, 10, 21, 8, 33, 28, "+04:00")
|
444
|
-
@user_clone.time_value = new_time_value
|
445
|
-
@user_clone.save!
|
446
|
-
|
447
|
-
@user.reload
|
448
|
-
assert_equal new_time_value, @user.time_value
|
449
|
-
end
|
450
|
-
end
|
451
|
-
|
452
|
-
context "date values" do
|
453
|
-
should "return correct data type" do
|
454
|
-
assert_equal @date_value, @user_clone.date_value
|
455
|
-
assert @user.clone.date_value.kind_of?(Date)
|
456
|
-
end
|
457
|
-
|
458
|
-
should "coerce data type before save" do
|
459
|
-
now = Time.now
|
460
|
-
u = User.new(:date_value => now)
|
461
|
-
assert_equal now.to_date, u.date_value
|
462
|
-
assert u.date_value.kind_of?(Date)
|
463
|
-
end
|
464
|
-
|
465
|
-
should "permit replacing value with nil" do
|
466
|
-
@user_clone.date_value = nil
|
467
|
-
@user_clone.save!
|
468
|
-
|
469
|
-
@user.reload
|
470
|
-
assert_nil @user.date_value
|
471
|
-
assert_nil @user.encrypted_date_value
|
472
|
-
end
|
473
|
-
|
474
|
-
should "permit replacing value" do
|
475
|
-
new_date_value = Date.new(1998, 10, 21)
|
476
|
-
@user_clone.date_value = new_date_value
|
477
|
-
@user_clone.save!
|
478
|
-
|
479
|
-
@user.reload
|
480
|
-
assert_equal new_date_value, @user.date_value
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
context "true values" do
|
485
|
-
should "return correct data type" do
|
486
|
-
assert_equal true, @user_clone.true_value
|
487
|
-
assert @user.clone.true_value.kind_of?(TrueClass)
|
488
|
-
end
|
489
|
-
|
490
|
-
should "coerce data type before save" do
|
491
|
-
u = User.new(:true_value => "1")
|
492
|
-
assert_equal true, u.true_value
|
493
|
-
assert u.true_value.kind_of?(TrueClass)
|
494
|
-
end
|
495
|
-
|
496
|
-
should "permit replacing value with nil" do
|
497
|
-
@user_clone.true_value = nil
|
498
|
-
@user_clone.save!
|
499
|
-
|
500
|
-
@user.reload
|
501
|
-
assert_nil @user.true_value
|
502
|
-
assert_nil @user.encrypted_true_value
|
503
|
-
end
|
504
|
-
|
505
|
-
should "permit replacing value" do
|
506
|
-
new_value = false
|
507
|
-
@user_clone.true_value = new_value
|
508
|
-
@user_clone.save!
|
509
|
-
|
510
|
-
@user.reload
|
511
|
-
assert_equal new_value, @user.true_value
|
512
|
-
end
|
513
|
-
end
|
514
|
-
|
515
|
-
context "false values" do
|
516
|
-
should "return correct data type" do
|
517
|
-
assert_equal false, @user_clone.false_value
|
518
|
-
assert @user.clone.false_value.kind_of?(FalseClass)
|
519
|
-
end
|
520
|
-
|
521
|
-
should "coerce data type before save" do
|
522
|
-
u = User.new(:false_value => "0")
|
523
|
-
assert_equal false, u.false_value
|
524
|
-
assert u.false_value.kind_of?(FalseClass)
|
525
|
-
end
|
526
|
-
|
527
|
-
should "permit replacing value with nil" do
|
528
|
-
@user_clone.false_value = nil
|
529
|
-
@user_clone.save!
|
530
|
-
|
531
|
-
@user.reload
|
532
|
-
assert_nil @user.false_value
|
533
|
-
assert_nil @user.encrypted_false_value
|
534
|
-
end
|
535
|
-
|
536
|
-
should "permit replacing value" do
|
537
|
-
new_value = true
|
538
|
-
@user_clone.false_value = new_value
|
539
|
-
@user_clone.save!
|
540
|
-
|
541
|
-
@user.reload
|
542
|
-
assert_equal new_value, @user.false_value
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
|
-
context "JSON Serialization" do
|
547
|
-
setup do
|
548
|
-
# JSON Does not support symbols, so they will come back as strings
|
549
|
-
# Convert symbols to string in the test
|
550
|
-
@h.keys.each do |k|
|
551
|
-
@h[k.to_s] = @h[k]
|
552
|
-
@h.delete(k)
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
|
-
should "return correct data type" do
|
557
|
-
assert_equal @h, @user_clone.data_json
|
558
|
-
assert @user.clone.data_json.kind_of?(Hash)
|
559
|
-
end
|
560
|
-
|
561
|
-
should "not coerce data type (leaves as hash) before save" do
|
562
|
-
u = User.new(:data_json => @h)
|
563
|
-
assert_equal @h, u.data_json
|
564
|
-
assert u.data_json.kind_of?(Hash)
|
565
|
-
end
|
566
|
-
|
567
|
-
should "permit replacing value with nil" do
|
568
|
-
@user_clone.data_json = nil
|
569
|
-
@user_clone.save!
|
570
|
-
|
571
|
-
@user.reload
|
572
|
-
assert_nil @user.data_json
|
573
|
-
assert_nil @user.encrypted_data_json
|
574
|
-
end
|
575
|
-
|
576
|
-
should "permit replacing value" do
|
577
|
-
new_value = @h.clone
|
578
|
-
new_value['c'] = 'C'
|
579
|
-
@user_clone.data_json = new_value
|
580
|
-
@user_clone.save!
|
581
|
-
|
582
|
-
@user.reload
|
583
|
-
assert_equal new_value, @user.data_json
|
584
|
-
end
|
585
|
-
end
|
586
|
-
|
587
|
-
context "YAML Serialization" do
|
588
|
-
should "return correct data type" do
|
589
|
-
assert_equal @h, @user_clone.data_yaml
|
590
|
-
assert @user.clone.data_yaml.kind_of?(Hash)
|
591
|
-
end
|
592
|
-
|
593
|
-
should "not coerce data type (leaves as hash) before save" do
|
594
|
-
u = User.new(:data_yaml => @h)
|
595
|
-
assert_equal @h, u.data_yaml
|
596
|
-
assert u.data_yaml.kind_of?(Hash)
|
597
|
-
end
|
598
|
-
|
599
|
-
should "permit replacing value with nil" do
|
600
|
-
@user_clone.data_yaml = nil
|
601
|
-
@user_clone.save!
|
602
|
-
|
603
|
-
@user.reload
|
604
|
-
assert_nil @user.data_yaml
|
605
|
-
assert_nil @user.encrypted_data_yaml
|
606
|
-
end
|
607
|
-
|
608
|
-
should "permit replacing value" do
|
609
|
-
new_value = @h.clone
|
610
|
-
new_value[:c] = 'C'
|
611
|
-
@user_clone.data_yaml = new_value
|
612
|
-
@user_clone.save!
|
613
|
-
|
614
|
-
@user.reload
|
615
|
-
assert_equal new_value, @user.data_yaml
|
616
|
-
end
|
617
|
-
end
|
618
|
-
|
619
|
-
end
|
620
|
-
end
|
621
|
-
end
|
622
|
-
end
|