attr_encrypted 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../test_helper', __FILE__)
3
+
4
+ # Test to ensure that existing representations in database do not break on
5
+ # migrating to new versions of this gem. This ensures that future versions of
6
+ # this gem will retain backwards compatibility with data generated by earlier
7
+ # versions.
8
+ class LegacyCompatibilityTest < Test::Unit::TestCase
9
+ class LegacyNonmarshallingPet < ActiveRecord::Base
10
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
11
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
12
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
13
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
14
+
15
+ attr_encrypted :nickname,
16
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY) }
17
+ attr_encrypted :birthdate,
18
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY) }
19
+ end
20
+
21
+ class LegacyMarshallingPet < ActiveRecord::Base
22
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
23
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
24
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
25
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
26
+
27
+ attr_encrypted :nickname,
28
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY) },
29
+ :marshal => true
30
+ attr_encrypted :birthdate,
31
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY) },
32
+ :marshal => true
33
+ end
34
+
35
+ def setup
36
+ ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
37
+ create_tables
38
+ end
39
+
40
+ def test_nonmarshalling_backwards_compatibility
41
+ pet = LegacyNonmarshallingPet.create!(
42
+ :name => 'Fido',
43
+ :encrypted_nickname => 'uSUB6KGzta87yxesyVc3DA==',
44
+ :encrypted_birthdate => 'I3d691B2PtFXLx15kO067g=='
45
+ )
46
+
47
+ assert_equal 'Fido', pet.name
48
+ assert_equal 'Fido the Dog', pet.nickname
49
+ assert_equal '2011-07-09', pet.birthdate
50
+ end
51
+
52
+ def test_marshalling_backwards_compatibility
53
+ # Marshalling formats changed significantly from Ruby 1.8.7 to 1.9.3.
54
+ # Also, Date class did not correctly support marshalling pre-1.9.3, so here
55
+ # we just marshal it as a string in the Ruby 1.8.7 case.
56
+ if RUBY_VERSION < '1.9.3'
57
+ pet = LegacyMarshallingPet.create!(
58
+ :name => 'Fido',
59
+ :encrypted_nickname => 'xhayxWxfkfbNyOS2w1qBMPV49Gfvs6dcZFBopMK2zQA=',
60
+ :encrypted_birthdate => 'f4ufXun4GXzahH4MQ1eTBQ=='
61
+ )
62
+ else
63
+ pet = LegacyMarshallingPet.create!(
64
+ :name => 'Fido',
65
+ :encrypted_nickname => '7RwoT64in4H+fGVBPYtRcN0K4RtriIy1EP4nDojUa8g=',
66
+ :encrypted_birthdate => 'bSp9sJhXQSp2QlNZHiujtcK4lRVBE8HQhn1y7moQ63bGJR20hvRSZ73ePAmm+wc5'
67
+ )
68
+ end
69
+
70
+ assert_equal 'Fido', pet.name
71
+ assert_equal 'Mummy\'s little helper', pet.nickname
72
+
73
+ # See earlier comment.
74
+ if RUBY_VERSION < '1.9.3'
75
+ assert_equal '2011-07-09', pet.birthdate
76
+ else
77
+ assert_equal Date.new(2011, 7, 9), pet.birthdate
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def create_tables
84
+ silence_stream(STDOUT) do
85
+ ActiveRecord::Schema.define(:version => 1) do
86
+ create_table :legacy_nonmarshalling_pets do |t|
87
+ t.string :name
88
+ t.string :encrypted_nickname
89
+ t.string :encrypted_birthdate
90
+ t.string :salt
91
+ end
92
+ create_table :legacy_marshalling_pets do |t|
93
+ t.string :name
94
+ t.string :encrypted_nickname
95
+ t.string :encrypted_birthdate
96
+ t.string :salt
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
104
+
@@ -0,0 +1,52 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ DataMapper.setup(:default, 'sqlite3::memory:')
4
+
5
+ class LegacyClient
6
+ include DataMapper::Resource
7
+
8
+ property :id, Serial
9
+ property :encrypted_email, String
10
+ property :encrypted_credentials, Text
11
+ property :salt, String
12
+
13
+ attr_encrypted :email, :key => 'a secret key'
14
+ attr_encrypted :credentials, :key => Proc.new { |client| Encryptor.encrypt(:value => client.salt, :key => 'some private key') }, :marshal => true
15
+
16
+ def initialize(attrs = {})
17
+ super attrs
18
+ self.salt ||= Digest::SHA1.hexdigest((Time.now.to_i * rand(5)).to_s)
19
+ self.credentials ||= { :username => 'example', :password => 'test' }
20
+ end
21
+ end
22
+
23
+ DataMapper.auto_migrate!
24
+
25
+ class LegacyDataMapperTest < Test::Unit::TestCase
26
+
27
+ def setup
28
+ LegacyClient.all.each(&:destroy)
29
+ end
30
+
31
+ def test_should_encrypt_email
32
+ @client = LegacyClient.new :email => 'test@example.com'
33
+ assert @client.save
34
+ assert_not_nil @client.encrypted_email
35
+ assert_not_equal @client.email, @client.encrypted_email
36
+ assert_equal @client.email, LegacyClient.first.email
37
+ end
38
+
39
+ def test_should_marshal_and_encrypt_credentials
40
+ @client = LegacyClient.new
41
+ assert @client.save
42
+ assert_not_nil @client.encrypted_credentials
43
+ assert_not_equal @client.credentials, @client.encrypted_credentials
44
+ assert_equal @client.credentials, LegacyClient.first.credentials
45
+ assert LegacyClient.first.credentials.is_a?(Hash)
46
+ end
47
+
48
+ def test_should_encode_by_default
49
+ assert LegacyClient.attr_encrypted_options[:encode]
50
+ end
51
+
52
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ DB.create_table :legacy_humans do
4
+ primary_key :id
5
+ column :encrypted_email, :string
6
+ column :password, :string
7
+ column :encrypted_credentials, :string
8
+ column :salt, :string
9
+ end
10
+
11
+ class LegacyHuman < Sequel::Model(:legacy_humans)
12
+ attr_encrypted :email, :key => 'a secret key'
13
+ attr_encrypted :credentials, :key => Proc.new { |human| Encryptor.encrypt(:value => human.salt, :key => 'some private key') }, :marshal => true
14
+
15
+ def after_initialize(attrs = {})
16
+ self.salt ||= Digest::SHA1.hexdigest((Time.now.to_i * rand(5)).to_s)
17
+ self.credentials ||= { :username => 'example', :password => 'test' }
18
+ end
19
+ end
20
+
21
+ class LegacySequelTest < Test::Unit::TestCase
22
+
23
+ def setup
24
+ LegacyHuman.all.each(&:destroy)
25
+ end
26
+
27
+ def test_should_encrypt_email
28
+ @human = LegacyHuman.new :email => 'test@example.com'
29
+ assert @human.save
30
+ assert_not_nil @human.encrypted_email
31
+ assert_not_equal @human.email, @human.encrypted_email
32
+ assert_equal @human.email, LegacyHuman.first.email
33
+ end
34
+
35
+ def test_should_marshal_and_encrypt_credentials
36
+ @human = LegacyHuman.new
37
+ assert @human.save
38
+ assert_not_nil @human.encrypted_credentials
39
+ assert_not_equal @human.credentials, @human.encrypted_credentials
40
+ assert_equal @human.credentials, LegacyHuman.first.credentials
41
+ assert LegacyHuman.first.credentials.is_a?(Hash)
42
+ end
43
+
44
+ def test_should_encode_by_default
45
+ assert LegacyHuman.attr_encrypted_options[:encode]
46
+ end
47
+
48
+ end
data/test/sequel_test.rb CHANGED
@@ -1,21 +1,23 @@
1
1
  require File.expand_path('../test_helper', __FILE__)
2
2
 
3
- DB = Sequel.sqlite
4
-
5
3
  DB.create_table :humans do
6
4
  primary_key :id
7
5
  column :encrypted_email, :string
6
+ column :encrypted_email_salt, String
7
+ column :encrypted_email_iv, :string
8
8
  column :password, :string
9
9
  column :encrypted_credentials, :string
10
- column :salt, :string
10
+ column :encrypted_credentials_iv, :string
11
+ column :encrypted_credentials_salt, String
11
12
  end
12
13
 
13
- class Human < Sequel::Model(:humans)
14
- attr_encrypted :email, :key => 'a secret key'
15
- attr_encrypted :credentials, :key => Proc.new { |human| Encryptor.encrypt(:value => human.salt, :key => 'some private key') }, :marshal => true
14
+ class Human < Sequel::Model(:humans)
15
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
16
+
17
+ attr_encrypted :email, :key => SECRET_KEY
18
+ attr_encrypted :credentials, :key => SECRET_KEY, :marshal => true
16
19
 
17
20
  def after_initialize(attrs = {})
18
- self.salt ||= Digest::SHA1.hexdigest((Time.now.to_i * rand(5)).to_s)
19
21
  self.credentials ||= { :username => 'example', :password => 'test' }
20
22
  end
21
23
  end
@@ -35,7 +37,8 @@ class SequelTest < Test::Unit::TestCase
35
37
  end
36
38
 
37
39
  def test_should_marshal_and_encrypt_credentials
38
- @human = Human.new
40
+
41
+ @human = Human.new :credentials => { :username => 'example', :password => 'test' }
39
42
  assert @human.save
40
43
  assert_not_nil @human.encrypted_credentials
41
44
  assert_not_equal @human.credentials, @human.encrypted_credentials
@@ -47,4 +50,4 @@ class SequelTest < Test::Unit::TestCase
47
50
  assert Human.attr_encrypted_options[:encode]
48
51
  end
49
52
 
50
- end
53
+ end
data/test/test_helper.rb CHANGED
@@ -1,3 +1,17 @@
1
+ if RUBY_VERSION >= '1.9.3'
2
+ require 'simplecov'
3
+ require 'simplecov-rcov'
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ SimpleCov::Formatter::RcovFormatter,
8
+ ]
9
+
10
+ SimpleCov.start do
11
+ add_filter 'test'
12
+ end
13
+ end
14
+
1
15
  require 'test/unit'
2
16
  require 'digest/sha2'
3
17
  require 'rubygems'
@@ -11,4 +25,15 @@ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
25
  $:.unshift(File.dirname(__FILE__))
12
26
  require 'attr_encrypted'
13
27
 
14
- puts "\nTesting with ActiveRecord #{ActiveRecord::VERSION::STRING rescue ENV['ACTIVE_RECORD_VERSION']}"
28
+ puts "\nTesting with ActiveRecord #{ActiveRecord::VERSION::STRING rescue ENV['ACTIVE_RECORD_VERSION']}"
29
+
30
+ DB = Sequel.sqlite
31
+
32
+ # The :after_initialize hook was removed in Sequel 4.0
33
+ # and had been deprecated for a while before that:
34
+ # http://sequel.rubyforge.org/rdoc-plugins/classes/Sequel/Plugins/AfterInitialize.html
35
+ # This plugin re-enables it.
36
+ Sequel::Model.plugin :after_initialize
37
+
38
+ SECRET_KEY = 4.times.map { Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s) }.join
39
+
metadata CHANGED
@@ -1,15 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attr_encrypted
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Sean Huber
9
+ - S. Brent Faulkner
10
+ - William Monk
9
11
  autorequire:
10
12
  bindir: bin
11
13
  cert_chain: []
12
- date: 2012-09-11 00:00:00.000000000 Z
14
+ date: 2013-11-14 00:00:00.000000000 Z
13
15
  dependencies:
14
16
  - !ruby/object:Gem::Dependency
15
17
  name: encryptor
@@ -18,7 +20,7 @@ dependencies:
18
20
  requirements:
19
21
  - - ! '>='
20
22
  - !ruby/object:Gem::Version
21
- version: 1.1.1
23
+ version: 1.3.0
22
24
  type: :runtime
23
25
  prerelease: false
24
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +28,7 @@ dependencies:
26
28
  requirements:
27
29
  - - ! '>='
28
30
  - !ruby/object:Gem::Version
29
- version: 1.1.1
31
+ version: 1.3.0
30
32
  - !ruby/object:Gem::Dependency
31
33
  name: activerecord
32
34
  requirement: !ruby/object:Gem::Requirement
@@ -91,8 +93,91 @@ dependencies:
91
93
  - - ! '>='
92
94
  - !ruby/object:Gem::Version
93
95
  version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: sqlite3
98
+ requirement: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: dm-sqlite-adapter
114
+ requirement: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ - !ruby/object:Gem::Dependency
129
+ name: rake
130
+ requirement: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - '='
134
+ - !ruby/object:Gem::Version
135
+ version: 0.9.2.2
136
+ type: :development
137
+ prerelease: false
138
+ version_requirements: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - '='
142
+ - !ruby/object:Gem::Version
143
+ version: 0.9.2.2
144
+ - !ruby/object:Gem::Dependency
145
+ name: simplecov
146
+ requirement: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ - !ruby/object:Gem::Dependency
161
+ name: simplecov-rcov
162
+ requirement: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ! '>='
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ type: :development
169
+ prerelease: false
170
+ version_requirements: !ruby/object:Gem::Requirement
171
+ none: false
172
+ requirements:
173
+ - - ! '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
94
176
  description: Generates attr_accessors that encrypt and decrypt attributes transparently
95
- email: shuber@huberry.com
177
+ email:
178
+ - shuber@huberry.com
179
+ - sbfaulkner@gmail.com
180
+ - billy.monk@gmail.com
96
181
  executables: []
97
182
  extensions: []
98
183
  extra_rdoc_files: []
@@ -107,10 +192,16 @@ files:
107
192
  - README.rdoc
108
193
  - test/active_record_test.rb
109
194
  - test/attr_encrypted_test.rb
195
+ - test/compatibility_test.rb
110
196
  - test/data_mapper_test.rb
197
+ - test/legacy_active_record_test.rb
198
+ - test/legacy_attr_encrypted_test.rb
199
+ - test/legacy_compatibility_test.rb
200
+ - test/legacy_data_mapper_test.rb
201
+ - test/legacy_sequel_test.rb
111
202
  - test/sequel_test.rb
112
203
  - test/test_helper.rb
113
- homepage: http://github.com/shuber/attr_encrypted
204
+ homepage: http://github.com/attr_encrypted/attr_encrypted
114
205
  licenses: []
115
206
  post_install_message:
116
207
  rdoc_options:
@@ -126,12 +217,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
217
  - - ! '>='
127
218
  - !ruby/object:Gem::Version
128
219
  version: '0'
220
+ segments:
221
+ - 0
222
+ hash: -52694865588709361
129
223
  required_rubygems_version: !ruby/object:Gem::Requirement
130
224
  none: false
131
225
  requirements:
132
226
  - - ! '>='
133
227
  - !ruby/object:Gem::Version
134
228
  version: '0'
229
+ segments:
230
+ - 0
231
+ hash: -52694865588709361
135
232
  requirements: []
136
233
  rubyforge_project:
137
234
  rubygems_version: 1.8.23
@@ -141,6 +238,12 @@ summary: Encrypt and decrypt attributes
141
238
  test_files:
142
239
  - test/active_record_test.rb
143
240
  - test/attr_encrypted_test.rb
241
+ - test/compatibility_test.rb
144
242
  - test/data_mapper_test.rb
243
+ - test/legacy_active_record_test.rb
244
+ - test/legacy_attr_encrypted_test.rb
245
+ - test/legacy_compatibility_test.rb
246
+ - test/legacy_data_mapper_test.rb
247
+ - test/legacy_sequel_test.rb
145
248
  - test/sequel_test.rb
146
249
  - test/test_helper.rb