attr_encrypted 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +14 -16
  3. data/CHANGELOG.md +60 -14
  4. data/README.md +27 -9
  5. data/Rakefile +3 -0
  6. data/attr_encrypted.gemspec +6 -13
  7. data/checksum/attr_encrypted-3.0.0.gem.sha256 +1 -0
  8. data/checksum/attr_encrypted-3.0.0.gem.sha512 +1 -0
  9. data/checksum/attr_encrypted-3.0.1.gem.sha256 +1 -0
  10. data/checksum/attr_encrypted-3.0.1.gem.sha512 +1 -0
  11. data/checksum/attr_encrypted-3.0.2.gem.sha256 +1 -0
  12. data/checksum/attr_encrypted-3.0.2.gem.sha512 +1 -0
  13. data/checksum/attr_encrypted-3.0.3.gem.sha256 +1 -0
  14. data/checksum/attr_encrypted-3.0.3.gem.sha512 +1 -0
  15. data/checksum/attr_encrypted-3.1.0.gem.sha256 +1 -0
  16. data/checksum/attr_encrypted-3.1.0.gem.sha512 +1 -0
  17. data/lib/attr_encrypted/adapters/active_record.rb +58 -30
  18. data/lib/attr_encrypted/adapters/data_mapper.rb +3 -1
  19. data/lib/attr_encrypted/adapters/sequel.rb +3 -1
  20. data/lib/attr_encrypted/version.rb +3 -1
  21. data/lib/attr_encrypted.rb +160 -129
  22. data/test/active_record_test.rb +130 -104
  23. data/test/attr_encrypted_test.rb +113 -16
  24. data/test/compatibility_test.rb +21 -21
  25. data/test/data_mapper_test.rb +2 -0
  26. data/test/legacy_active_record_test.rb +9 -9
  27. data/test/legacy_attr_encrypted_test.rb +8 -6
  28. data/test/legacy_compatibility_test.rb +15 -15
  29. data/test/legacy_data_mapper_test.rb +2 -0
  30. data/test/legacy_sequel_test.rb +2 -0
  31. data/test/run.sh +15 -7
  32. data/test/sequel_test.rb +2 -0
  33. data/test/test_helper.rb +11 -5
  34. metadata +27 -50
  35. checksums.yaml.gz.sig +0 -0
  36. data/certs/saghaulor.pem +0 -21
  37. data.tar.gz.sig +0 -0
  38. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7818979e143dc8810acdc45dfe6ae67273be455d
4
- data.tar.gz: 734c97e4b7d4109b40f4f6bdf7c34aace6e3be3b
2
+ SHA256:
3
+ metadata.gz: 36ebe1f889eadcc15b60089547792d023a5b32e4877a17789da28bc2ca33b3c1
4
+ data.tar.gz: 54540410056e0b49d7cc6af2077af4e45cf06aef354e0780757b93ff4af1e134
5
5
  SHA512:
6
- metadata.gz: 6d8458d63ccd20fbeb9ae4d79689e0a90d3007bd0a212c428c9b95b44d20f39c5e038215bac1e5c7af1138f2517faf7a96973167b213be289a6b5fc7c1b75918
7
- data.tar.gz: 57201322d4c3dcbf30bf5c74f931b47bf6478626e925620497fc842d87c393aeb507d277c92f524ff233d515acafad1d367ecb3427250ace7d125a9e3ecb1ab8
6
+ metadata.gz: 55a0639ffee8def55645e2444d063ab18df7030f74404289735b2e9329ff65461ac0af3dab29248c337f9b5344aeb7c78d72f3d9155edabde689997c519c88b2
7
+ data.tar.gz: 22af4440292a3950cb2ca1ab4ed795972626fb974b962d5dc86ebec5492fb7f3a83b691d2432d691d39de66df0a244bfce31576af0b58ab65881b8faf1db8323
data/.travis.yml CHANGED
@@ -1,24 +1,22 @@
1
- sudo: false
2
1
  language: ruby
2
+ dist: focal
3
+ os: linux
3
4
  cache: bundler
4
5
  rvm:
5
- - 2.0
6
- - 2.1
7
- - 2.2
8
- - 2.3.0
9
- - rbx
6
+ - 2.6.10
7
+ - 2.7.6
10
8
  env:
11
- - ACTIVERECORD=3.0.0
12
- - ACTIVERECORD=3.1.0
13
- - ACTIVERECORD=3.2.0
14
- - ACTIVERECORD=4.0.0
15
- - ACTIVERECORD=4.1.0
16
- - ACTIVERECORD=4.2.0
17
- matrix:
9
+ - ACTIVERECORD=5.1.1
10
+ - ACTIVERECORD=5.2.8
11
+ - ACTIVERECORD=6.0.6
12
+ - ACTIVERECORD=6.1.7
13
+ - ACTIVERECORD=7.0.4
14
+ jobs:
15
+ fast_finish: false
18
16
  exclude:
19
- allow_failures:
20
- - rvm: rbx
21
- fast_finish: true
17
+ - rvm: 2.6.10
18
+ env: ACTIVERECORD=7.0.4
19
+
22
20
  addons:
23
21
  code_climate:
24
22
  repo_token: a90435ed4954dd6e9f3697a20c5bc3754f67d94703f870e8fc7b00f69f5b2d06
data/CHANGELOG.md CHANGED
@@ -1,11 +1,46 @@
1
- # attr_encrypted #
1
+ # attr_encrypted
2
+
3
+ ## 4.0.0
4
+
5
+ * Added: Support for Ruby >= 3.0.
6
+ * Added: Rails 7 support.
7
+ * Changed: Using `#encrypted_attributes` is no longer supported. Instead, use `#attr_encrypted_encrypted_attributes` to avoid
8
+ collision with Active Record 7 native encryption.
9
+
10
+ ## 3.1.0
11
+
12
+ * Added: Abitilty to encrypt empty values. (@tamird)
13
+ * Added: MIT license
14
+ * Added: MRI 2.5.x support (@saghaulor)
15
+ * Fixed: No long generate IV and salt if value is empty, unless :allow_empty_value options is passed. (@saghaulor)
16
+ * Fixed: Only generate IV and salt when :if and :unless options evaluate such that encryption should be performed. (@saghaulor)
17
+ * Fixed: Private methods are correctly evaluated as options. (@saghaulor)
18
+ * Fixed: Mark virtual attributes for Rails 5.x compatibility (@grosser)
19
+ * Fixed: Only check empty on strings, allows for encrypting non-string type objects
20
+ * Fixed: Fixed how accessors for db columns are defined in the ActiveRecord adapter, preventing premature definition. (@nagachika)
21
+
22
+ ## 3.0.3
23
+
24
+ * Fixed: attr_was would decrypt the attribute upon every call. This is inefficient and introduces problems when the options change between decrypting an old value and encrypting a new value; for example, when rotating the encryption key. As such, the new approach caches the decrypted value of the old encrypted value such that the old options are no longer needed. (@johnny-lai) (@saghaulor)
25
+
26
+ ## 3.0.2
27
+
28
+ * Changed: Removed alias_method_chain for compatibility with Rails v5.x (@grosser)
29
+ * Changed: Updated Travis build matrix to include Rails 5. (@saghaulor) (@connorshea)
30
+ * Changed: Removed `.silence_stream` from tests as it has been removed from Rails 5. (@sblackstone)
31
+
32
+ ## 3.0.1
33
+
34
+ * Fixed: attr_was method no longer calls undefined methods. (@saghaulor)
35
+
36
+ ## 3.0.0
2
37
 
3
- ## 3.0.0 ##
4
38
  * Changed: Updated gemspec to use Encryptor v3.0.0. (@saghaulor)
5
39
  * Changed: Updated README with instructions related to moving from v2.0.0 to v3.0.0. (@saghaulor)
6
40
  * Fixed: ActiveModel::Dirty methods in the ActiveRecord adapter. (@saghaulor)
7
41
 
8
- ## 2.0.0 ##
42
+ ## 2.0.0
43
+
9
44
  * Added: Now using Encryptor v2.0.0 (@saghaulor)
10
45
  * Added: Options are copied to the instance. (@saghaulor)
11
46
  * Added: Operation option is set during encryption/decryption to allow options to be evaluated in the context of the current operation. (@saghaulor)
@@ -26,51 +61,62 @@
26
61
  * Removed: Support for Rails < 3.x (@saghaulor)
27
62
  * Removed: Unnecessary use of `alias_method` from ActiveRecord adapter. (@saghaulor)
28
63
 
29
- ## 1.4.0 ##
64
+ ## 1.4.0
65
+
30
66
  * Added: ActiveModel::Dirty#attribute_was (@saghaulor)
31
67
  * Added: ActiveModel::Dirty#attribute_changed? (@mwean)
32
68
 
33
- ## 1.3.5 ##
69
+ ## 1.3.5
70
+
34
71
  * Changed: Fixed gemspec to explicitly depend on Encryptor v1.3.0 (@saghaulor)
35
72
  * Fixed: Evaluate `:mode` option as a symbol or proc. (@cheynewallace)
36
73
 
37
- ## 1.3.4 ##
74
+ ## 1.3.4
75
+
38
76
  * Added: ActiveRecord::Base.reload support. (@rcook)
39
77
  * Fixed: ActiveRecord adapter no longer forces attribute hashes to be string-keyed. (@tamird)
40
78
  * Fixed: Mass assignment protection in ActiveRecord 4. (@tamird)
41
79
  * Changed: Now using rubygems over https. (@tamird)
42
80
  * Changed: Let ActiveRecord define attribute methods. (@saghaulor)
43
81
 
44
- ## 1.3.3 ##
82
+ ## 1.3.3
83
+
45
84
  * Added: Alias attr_encryptor and attr_encrpted. (@Billy Monk)
46
85
 
47
- ## 1.3.2 ##
86
+ ## 1.3.2
87
+
48
88
  * Fixed: Bug regarding strong parameters. (@S. Brent Faulkner)
49
89
  * Fixed: Bug regarding loading per instance IV and salt. (@S. Brent Faulkner)
50
90
  * Fixed: Bug regarding assigning nil. (@S. Brent Faulkner)
51
91
  * Added: Support for protected attributes. (@S. Brent Faulkner)
52
92
  * Added: Support for ActiveRecord 4. (@S. Brent Faulkner)
53
93
 
54
- ## 1.3.1 ##
94
+ ## 1.3.1
95
+
55
96
  * Added: Support for Rails 2.3.x and 3.1.x. (@S. Brent Faulkner)
56
97
 
57
- ## 1.3.0 ##
98
+ ## 1.3.0
99
+
58
100
  * Fixed: Serialization bug. (@Billy Monk)
59
101
  * Added: Support for :per_attribute_iv_and_salt mode. (@rcook)
60
102
  * Fixed: Added dependencies to gemspec. (@jmazzi)
61
103
 
62
- ## 1.2.1 ##
104
+ ## 1.2.1
105
+
63
106
  * Added: Force encoding when not marshaling. (@mosaicxm)
64
107
  * Fixed: Issue specifying multiple attributes on the same line. (@austintaylor)
65
108
  * Added: Typecasting to String before encryption (@shuber)
66
109
  * Added: `"#{attribute}?"` method. (@shuber)
67
110
 
68
- ## 1.2.0 ##
111
+ ## 1.2.0
112
+
69
113
  * Changed: General code refactoring (@shuber)
70
114
 
71
- ## 1.1.2 ##
115
+ ## 1.1.2
116
+
72
117
  * No significant changes
73
118
 
74
- ## 1.1.1 ##
119
+ ## 1.1.1
120
+
75
121
  * Changled: Updated README. (@shuber)
76
122
  * Added: `before_type_cast` alias to ActiveRecord adapter. (@shuber)
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # attr_encrypted
2
+
2
3
  [![Build Status](https://secure.travis-ci.org/attr-encrypted/attr_encrypted.svg)](https://travis-ci.org/attr-encrypted/attr_encrypted) [![Test Coverage](https://codeclimate.com/github/attr-encrypted/attr_encrypted/badges/coverage.svg)](https://codeclimate.com/github/attr-encrypted/attr_encrypted/coverage) [![Code Climate](https://codeclimate.com/github/attr-encrypted/attr_encrypted/badges/gpa.svg)](https://codeclimate.com/github/attr-encrypted/attr_encrypted) [![Gem Version](https://badge.fury.io/rb/attr_encrypted.svg)](https://badge.fury.io/rb/attr_encrypted) [![security](https://hakiri.io/github/attr-encrypted/attr_encrypted/master.svg)](https://hakiri.io/github/attr-encrypted/attr_encrypted/master)
3
4
 
4
5
  Generates attr_accessors that transparently encrypt and decrypt attributes.
@@ -11,7 +12,7 @@ It works with ANY class, however, you get a few extra features when you're using
11
12
  Add attr_encrypted to your gemfile:
12
13
 
13
14
  ```ruby
14
- gem "attr_encrypted", "~> 3.0.0"
15
+ gem "attr_encrypted"
15
16
  ```
16
17
 
17
18
  Then install the gem:
@@ -72,7 +73,7 @@ The `attr_encrypted` class method is also aliased as `attr_encryptor` to conform
72
73
 
73
74
  ### attr_encrypted with database persistence
74
75
 
75
- By default, `attr_encrypted` uses the `:per_attribute_iv` encryption mode. This mode requires a column to store your cipher text and a column to store your IV.
76
+ By default, `attr_encrypted` uses the `:per_attribute_iv` encryption mode. This mode requires a column to store your cipher text and a column to store your IV (initialization vector).
76
77
 
77
78
  Create or modify the table that your model uses to add a column with the `encrypted_` prefix (which can be modified, see below), e.g. `encrypted_ssn` via a migration like the following:
78
79
 
@@ -87,6 +88,12 @@ Create or modify the table that your model uses to add a column with the `encryp
87
88
 
88
89
  You can use a string or binary column type. (See the encode option section below for more info)
89
90
 
91
+ If you use the same key for each record, add a unique index on the IV. Repeated IVs with AES-GCM (the default algorithm) allow an attacker to recover the key.
92
+
93
+ ```ruby
94
+ add_index :users, :encrypted_ssn_iv, unique: true
95
+ ```
96
+
90
97
  ### Specifying the encrypted attribute name
91
98
 
92
99
  By default, the encrypted attribute name is `encrypted_#{attribute}` (e.g. `attr_encrypted :email` would create an attribute named `encrypted_email`). So, if you're storing the encrypted attribute in the database, you need to make sure the `encrypted_#{attribute}` field exists in your table. You have a couple of options if you want to name your attribute or db column something else, see below for more details.
@@ -145,6 +152,7 @@ The following are the default options used by `attr_encrypted`:
145
152
  decrypt_method: 'decrypt',
146
153
  mode: :per_attribute_iv,
147
154
  algorithm: 'aes-256-gcm',
155
+ allow_empty_value: false
148
156
  ```
149
157
 
150
158
  All of the aforementioned options are explained in depth below.
@@ -195,7 +203,7 @@ If you don't like the `encrypted_#{attribute}` naming convention then you can sp
195
203
  end
196
204
  ```
197
205
 
198
- This would generate the following attributes: `secret_email_crypted`, `secret_credit_card_crypted`, and `secret_ssn_crypted`.
206
+ This would generate the following attribute: `secret_email_crypted`.
199
207
 
200
208
 
201
209
  ### The `:key` option
@@ -296,7 +304,7 @@ You're probably going to be storing your encrypted attributes somehow (e.g. file
296
304
  end
297
305
  ```
298
306
 
299
- The default encoding is `m` (base64). You can change this by setting `encode: 'some encoding'`. See [`Arrary#pack`](http://ruby-doc.org/core-2.3.0/Array.html#method-i-pack) for more encoding options.
307
+ The default encoding is `m` (base64). You can change this by setting `encode: 'some encoding'`. See [`Array#pack`](http://ruby-doc.org/core-2.3.0/Array.html#method-i-pack) for more encoding options.
300
308
 
301
309
 
302
310
  ### The `:marshal`, `:dump_method`, and `:load_method` options
@@ -311,6 +319,16 @@ You may want to encrypt objects other than strings (e.g. hashes, arrays, etc). I
311
319
 
312
320
  You may also optionally specify `:marshaler`, `:dump_method`, and `:load_method` if you want to use something other than the default `Marshal` object.
313
321
 
322
+ ### The `:allow_empty_value` option
323
+
324
+ You may want to encrypt empty strings or nil so as to not reveal which records are populated and which records are not.
325
+
326
+ ```ruby
327
+ class User
328
+ attr_encrypted :credentials, key: 'some secret key', marshal: true, allow_empty_value: true
329
+ end
330
+ ```
331
+
314
332
 
315
333
  ## ORMs
316
334
 
@@ -392,7 +410,7 @@ Then modify your models using attr\_encrypted to account for the changes in defa
392
410
 
393
411
  ## Upgrading from attr_encrypted v2.x to v3.x
394
412
 
395
- A bug was discovered in Encryptor v2.0.0 that inccorectly set the IV when using an AES-\*-GCM algorithm. Unfornately fixing this major security issue results in the inability to decrypt records encrypted using an AES-*-GCM algorithm from Encryptor v2.0.0. Please see [Upgrading to Encryptor v3.0.0](https://github.com/attr-encrypted/encryptor#upgrading-from-v200-to-v300) for more info.
413
+ A bug was discovered in Encryptor v2.0.0 that incorrectly set the IV when using an AES-\*-GCM algorithm. Unfornately fixing this major security issue results in the inability to decrypt records encrypted using an AES-*-GCM algorithm from Encryptor v2.0.0. Please see [Upgrading to Encryptor v3.0.0](https://github.com/attr-encrypted/encryptor#upgrading-from-v200-to-v300) for more info.
396
414
 
397
415
  It is strongly advised that you re-encrypt your data encrypted with Encryptor v2.0.0. However, you'll have to take special care to re-encrypt. To decrypt data encrypted with Encryptor v2.0.0 using an AES-\*-GCM algorithm you can use the `:v2_gcm_iv` option.
398
416
 
@@ -400,10 +418,10 @@ It is recommended that you implement a strategy to insure that you do not mix th
400
418
 
401
419
  ```ruby
402
420
  class User
403
- attr_encrypted :ssn, key: :encryption_key, v2_gcm_iv: :is_decrypting?(:ssn)
421
+ attr_encrypted :ssn, key: :encryption_key, v2_gcm_iv: is_decrypting?(:ssn)
404
422
 
405
423
  def is_decrypting?(attribute)
406
- encrypted_atributes[attribute][operation] == :decrypting
424
+ attr_encrypted_encrypted_attributes[attribute][:operation] == :decrypting
407
425
  end
408
426
  end
409
427
 
@@ -420,7 +438,7 @@ It is recommended that you implement a strategy to insure that you do not mix th
420
438
  While choosing to encrypt at the attribute level is the most secure solution, it is not without drawbacks. Namely, you cannot search the encrypted data, and because you can't search it, you can't index it either. You also can't use joins on the encrypted data. Data that is securely encrypted is effectively noise. So any operations that rely on the data not being noise will not work. If you need to do any of the aforementioned operations, please consider using database and file system encryption along with transport encryption as it moves through your stack.
421
439
 
422
440
  #### Data leaks
423
- Please also consider where your data leaks. If you're using attr_encrypted with Rails, it's highly likely that this data will enter your app as a request parameter. You'll want to be sure that you're filtering your request params from you logs or else your data is sitting in the clear in your logs. [Parameter Filtering in Rails](http://apidock.com/rails/ActionDispatch/Http/FilterParameters) Please also consider other possible leak points.
441
+ Please also consider where your data leaks. If you're using attr_encrypted with Rails, it's highly likely that this data will enter your app as a request parameter. You'll want to be sure that you're filtering your request params from your logs or else your data is sitting in the clear in your logs. [Parameter Filtering in Rails](http://apidock.com/rails/ActionDispatch/Http/FilterParameters) Please also consider other possible leak points.
424
442
 
425
443
  #### Storage requirements
426
444
  When storing your encrypted data, please consider the length requirements of the db column that you're storing the cipher text in. Older versions of Mysql attempt to 'help' you by truncating strings that are too large for the column. When this happens, you will not be able to decrypt your data. [MySQL Strict Trans](http://www.davidpashley.com/2009/02/15/silently-truncated/)
@@ -429,7 +447,7 @@ When storing your encrypted data, please consider the length requirements of the
429
447
  It is advisable to also store metadata regarding the circumstances of your encrypted data. Namely, you should store information about the key used to encrypt your data, as well as the algorithm. Having this metadata with every record will make key rotation and migrating to a new algorithm signficantly easier. It will allow you to continue to decrypt old data using the information provided in the metadata and new data can be encrypted using your new key and algorithm of choice.
430
448
 
431
449
  #### Enforcing the IV as a nonce
432
- On a related note, most alorithms require that your IV be unique for every record and key combination. You can enforce this using composite unique indexes on your IV and encryption key name/id column. [RFC 5084](https://tools.ietf.org/html/rfc5084#section-1.5)
450
+ On a related note, most algorithms require that your IV be unique for every record and key combination. You can enforce this using composite unique indexes on your IV and encryption key name/id column. [RFC 5084](https://tools.ietf.org/html/rfc5084#section-1.5)
433
451
 
434
452
  #### Unique key per record
435
453
  Lastly, while the `:per_attribute_iv_and_salt` mode is more secure than `:per_attribute_iv` mode because it uses a unique key per record, it uses a PBKDF function which introduces a huge performance hit (175x slower by my benchmarks). There are other ways of deriving a unique key per record that would be much faster.
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake/testtask'
2
4
  require 'rdoc/task'
3
5
  require "bundler/gem_tasks"
@@ -6,6 +8,7 @@ desc 'Test the attr_encrypted gem.'
6
8
  Rake::TestTask.new(:test) do |t|
7
9
  t.libs << 'lib'
8
10
  t.pattern = 'test/**/*_test.rb'
11
+ t.warning = false
9
12
  t.verbose = true
10
13
  end
11
14
 
@@ -17,16 +17,14 @@ Gem::Specification.new do |s|
17
17
  s.authors = ['Sean Huber', 'S. Brent Faulkner', 'William Monk', 'Stephen Aghaulor']
18
18
  s.email = ['seah@shuber.io', 'sbfaulkner@gmail.com', 'billy.monk@gmail.com', 'saghaulor@gmail.com']
19
19
  s.homepage = 'http://github.com/attr-encrypted/attr_encrypted'
20
-
21
- s.has_rdoc = false
22
- s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.rdoc']
20
+ s.license = 'MIT'
23
21
 
24
22
  s.require_paths = ['lib']
25
23
 
26
24
  s.files = `git ls-files`.split("\n")
27
25
  s.test_files = `git ls-files -- test/*`.split("\n")
28
26
 
29
- s.required_ruby_version = '>= 2.0.0'
27
+ s.required_ruby_version = '>= 2.6.0'
30
28
 
31
29
  s.add_dependency('encryptor', ['~> 3.0.0'])
32
30
  # support for testing with specific active record version
@@ -45,19 +43,14 @@ Gem::Specification.new do |s|
45
43
  s.add_development_dependency('activerecord-jdbcsqlite3-adapter')
46
44
  s.add_development_dependency('jdbc-sqlite3', '< 3.8.7') # 3.8.7 is nice and broke
47
45
  else
48
- s.add_development_dependency('sqlite3')
46
+ s.add_development_dependency('sqlite3', '= 1.5.4')
49
47
  end
50
48
  s.add_development_dependency('dm-sqlite-adapter')
49
+ s.add_development_dependency('pry')
51
50
  s.add_development_dependency('simplecov')
52
51
  s.add_development_dependency('simplecov-rcov')
53
- s.add_development_dependency("codeclimate-test-reporter")
54
-
55
- s.cert_chain = ['certs/saghaulor.pem']
56
- s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
57
52
 
58
- s.post_install_message = "\n\n\nWARNING: Several insecure default options and features were deprecated in attr_encrypted v2.0.0.\n
59
- Additionally, there was a bug in Encryptor v2.0.0 that insecurely encrypted data when using an AES-*-GCM algorithm.\n
60
- This bug was fixed but introduced breaking changes between v2.x and v3.x.\n
61
- Please see the README for more information regarding upgrading to attr_encrypted v3.0.0.\n\n\n"
53
+ s.post_install_message = "\n\n\nWARNING: Using `#encrypted_attributes` is no longer supported. Instead, use `#attr_encrypted_encrypted_attributes` to avoid
54
+ collision with Active Record 7 native encryption.\n\n\n"
62
55
 
63
56
  end
@@ -0,0 +1 @@
1
+ 845fc3cb09a19c3ac76192aba443788f92c880744617bca99b16fd31ce843e07
@@ -0,0 +1 @@
1
+ 81a065442258cc3702aab62c7b2307a48ed3e0deb803600d11a7480cce0db7c43fd9929acd2755081042f8989236553fd694b6cb62776bbfc53f9165a22cbca1
@@ -0,0 +1 @@
1
+ 33140af4b223177db7a19efb2fa38472a299a745b29ca1c5ba9d3fa947390b77
@@ -0,0 +1 @@
1
+ 0c467cab98b9b2eb331f9818323a90ae01392d6cb03cf1f32faccc954d0fc54be65f0fc7bf751b0fce57925eef1c9e2af90181bc40d81ad93e21d15a001c53c6
@@ -0,0 +1 @@
1
+ c1256b459336d4a2012a0d0c70ce5cd3dac46acb5e78da6f77f6f104cb1e8b7b
@@ -0,0 +1 @@
1
+ dca0c8a729974c0e26fde4cd4216c7d0f66d9eca9f6cf0ccca64999f5180a00bf7c05b630c1d420ec1673141a2923946e8bd28b12e711faf64a4cd42c7a3ac9e
@@ -0,0 +1 @@
1
+ 6d84c64852c4bbc0926b92fe7a93295671a9e69cb2939b96fb1e4b5e8a5b33b6
@@ -0,0 +1 @@
1
+ 0f960e8a2f63c747c273241f7395dcceb0dd8a6f79349bee453db741fc7ea5ceb4342d7d5908e540e3b5acea2216ff38bef8c743e6e7c8559bacb4a731ab27c4
@@ -0,0 +1 @@
1
+ 4f0682604714ed4599cf00771ad27e82f0b51b0ed8644af51a43d21fbe129b59
@@ -0,0 +1 @@
1
+ dc757a50c53175dc05adbfccb25b536f7f1a060c7bd626bfc72ff577479c6fe28d3b65747033276bd4bce3dad741b67235f3e01ea61409f6c67959da65df445b
@@ -1,45 +1,50 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(ActiveRecord::Base)
2
4
  module AttrEncrypted
3
5
  module Adapters
4
6
  module ActiveRecord
7
+ RAILS_VERSION = Gem::Version.new(::ActiveRecord::VERSION::STRING).freeze
8
+
5
9
  def self.extended(base) # :nodoc:
6
10
  base.class_eval do
7
11
 
8
12
  # https://github.com/attr-encrypted/attr_encrypted/issues/68
9
- def reload_with_attr_encrypted(*args, &block)
13
+ alias_method :reload_without_attr_encrypted, :reload
14
+ def reload(*args, &block)
10
15
  result = reload_without_attr_encrypted(*args, &block)
11
- self.class.encrypted_attributes.keys.each do |attribute_name|
16
+ self.class.attr_encrypted_encrypted_attributes.keys.each do |attribute_name|
12
17
  instance_variable_set("@#{attribute_name}", nil)
13
18
  end
14
19
  result
15
20
  end
16
- alias_method_chain :reload, :attr_encrypted
17
21
 
18
22
  attr_encrypted_options[:encode] = true
19
23
 
20
24
  class << self
21
- alias_method_chain :method_missing, :attr_encrypted
25
+ alias_method :method_missing_without_attr_encrypted, :method_missing
26
+ alias_method :method_missing, :method_missing_with_attr_encrypted
22
27
  end
23
28
 
24
29
  def perform_attribute_assignment(method, new_attributes, *args)
25
30
  return if new_attributes.blank?
26
31
 
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
32
+ send method, new_attributes.reject { |k, _| self.class.attr_encrypted_encrypted_attributes.key?(k.to_sym) }, *args
33
+ send method, new_attributes.reject { |k, _| !self.class.attr_encrypted_encrypted_attributes.key?(k.to_sym) }, *args
29
34
  end
30
35
  private :perform_attribute_assignment
31
36
 
32
- if ::ActiveRecord::VERSION::STRING > "3.1"
33
- def assign_attributes_with_attr_encrypted(*args)
37
+ if Gem::Requirement.new('> 3.1').satisfied_by?(RAILS_VERSION)
38
+ alias_method :assign_attributes_without_attr_encrypted, :assign_attributes
39
+ def assign_attributes(*args)
34
40
  perform_attribute_assignment :assign_attributes_without_attr_encrypted, *args
35
41
  end
36
- alias_method_chain :assign_attributes, :attr_encrypted
37
42
  end
38
43
 
39
- def attributes_with_attr_encrypted=(*args)
44
+ alias_method :attributes_without_attr_encrypted=, :attributes=
45
+ def attributes=(*args)
40
46
  perform_attribute_assignment :attributes_without_attr_encrypted=, *args
41
47
  end
42
- alias_method_chain :attributes=, :attr_encrypted
43
48
  end
44
49
  end
45
50
 
@@ -50,22 +55,42 @@ if defined?(ActiveRecord::Base)
50
55
  super
51
56
  options = attrs.extract_options!
52
57
  attr = attrs.pop
53
- options.merge! encrypted_attributes[attr]
58
+ attribute attr
59
+ options.merge! attr_encrypted_encrypted_attributes[attr]
54
60
 
55
- define_method("#{attr}_changed?") do
56
- if send("#{options[:attribute]}_changed?")
57
- send(attr) != send("#{attr}_was")
58
- end
61
+ define_method("#{attr}_was") do
62
+ attribute_was(attr)
59
63
  end
60
64
 
61
- define_method("#{attr}_was") do
62
- iv_and_salt = { iv: send("#{options[:attribute]}_iv_was"), salt: send("#{options[:attribute]}_salt_was"), operation: :decrypting }
63
- encrypted_attributes[attr].merge!(iv_and_salt)
64
- evaluated_options = evaluated_attr_encrypted_options_for(attr)
65
- [:iv, :salt, :operation].each { |key| encrypted_attributes[attr].delete(key) }
66
- self.class.decrypt(attr, send("#{options[:attribute]}_was"), evaluated_options)
65
+ define_method("#{attr}_changed?") do |options = {}|
66
+ attribute_changed?(attr, **options)
67
+ end
68
+
69
+ define_method("#{attr}_change") do
70
+ attribute_change(attr)
67
71
  end
68
72
 
73
+ define_method("#{attr}_with_dirtiness=") do |value|
74
+ ## Source: https://github.com/priyankatapar/attr_encrypted/commit/7e8702bd5418c927a39d8dd72c0adbea522d5663
75
+ # In ActiveRecord 5.2+, due to changes to the way virtual
76
+ # attributes are handled, @attributes[attr].value is nil which
77
+ # breaks attribute_was. Setting it here returns us to the expected
78
+ # behavior.
79
+ if RAILS_VERSION >= Gem::Version.new(5.2)
80
+ # This is needed support attribute_was before a record has
81
+ # been saved
82
+ @attributes.write_cast_value(attr.to_s, __send__(attr)) if value != __send__(attr)
83
+ # This is needed to support attribute_was after a record has
84
+ # been saved
85
+ @attributes.write_from_user(attr.to_s, value) if value != __send__(attr)
86
+ end
87
+ attribute_will_change!(attr) if value != __send__(attr)
88
+ __send__("#{attr}_without_dirtiness=", value)
89
+ end
90
+
91
+ alias_method "#{attr}_without_dirtiness=", "#{attr}="
92
+ alias_method "#{attr}=", "#{attr}_with_dirtiness="
93
+
69
94
  alias_method "#{attr}_before_type_cast", attr
70
95
  end
71
96
 
@@ -74,16 +99,17 @@ if defined?(ActiveRecord::Base)
74
99
  # methods returned to let ActiveRecord define the accessor methods
75
100
  # for the db columns
76
101
 
77
- # Use with_connection so the connection doesn't stay pinned to the thread.
78
- connected = ::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false
79
-
80
- if connected && table_exists?
102
+ if connected? && table_exists?
81
103
  columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
82
104
  else
83
105
  super
84
106
  end
85
107
  end
86
108
 
109
+ def attribute_instance_methods_as_symbols_available?
110
+ connected? && table_exists?
111
+ end
112
+
87
113
  # Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
88
114
  # encrypted attributes
89
115
  #
@@ -105,10 +131,10 @@ if defined?(ActiveRecord::Base)
105
131
  if match = /^(find|scoped)_(all_by|by)_([_a-zA-Z]\w*)$/.match(method.to_s)
106
132
  attribute_names = match.captures.last.split('_and_')
107
133
  attribute_names.each_with_index do |attribute, index|
108
- if attr_encrypted?(attribute) && encrypted_attributes[attribute.to_sym][:mode] == :single_iv_and_salt
134
+ if attr_encrypted?(attribute) && attr_encrypted_encrypted_attributes[attribute.to_sym][:mode] == :single_iv_and_salt
109
135
  args[index] = send("encrypt_#{attribute}", args[index])
110
136
  warn "DEPRECATION WARNING: This feature will be removed in the next major release."
111
- attribute_names[index] = encrypted_attributes[attribute.to_sym][:attribute]
137
+ attribute_names[index] = attr_encrypted_encrypted_attributes[attribute.to_sym][:attribute]
112
138
  end
113
139
  end
114
140
  method = "#{match.captures[0]}_#{match.captures[1]}_#{attribute_names.join('_and_')}".to_sym
@@ -119,6 +145,8 @@ if defined?(ActiveRecord::Base)
119
145
  end
120
146
  end
121
147
 
122
- ActiveRecord::Base.extend AttrEncrypted
123
- ActiveRecord::Base.extend AttrEncrypted::Adapters::ActiveRecord
148
+ ActiveSupport.on_load(:active_record) do
149
+ extend AttrEncrypted
150
+ extend AttrEncrypted::Adapters::ActiveRecord
151
+ end
124
152
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(DataMapper)
2
4
  module AttrEncrypted
3
5
  module Adapters
@@ -19,4 +21,4 @@ if defined?(DataMapper)
19
21
  end
20
22
 
21
23
  DataMapper::Resource.extend AttrEncrypted::Adapters::DataMapper
22
- end
24
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(Sequel)
2
4
  module AttrEncrypted
3
5
  module Adapters
@@ -11,4 +13,4 @@ if defined?(Sequel)
11
13
 
12
14
  Sequel::Model.extend AttrEncrypted
13
15
  Sequel::Model.extend AttrEncrypted::Adapters::Sequel
14
- end
16
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AttrEncrypted
2
4
  # Contains information about this gem's version
3
5
  module Version
4
- MAJOR = 3
6
+ MAJOR = 4
5
7
  MINOR = 0
6
8
  PATCH = 0
7
9