attr_encrypted 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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