attr_encrypted 3.0.3 → 3.1.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +29 -0
- data/CHANGELOG.md +11 -0
- data/README.md +15 -4
- data/Rakefile +1 -0
- data/attr_encrypted.gemspec +6 -1
- data/certs/saghaulor.pem +15 -15
- data/checksum/attr_encrypted-3.0.3.gem.sha256 +1 -0
- data/checksum/attr_encrypted-3.0.3.gem.sha512 +1 -0
- data/lib/attr_encrypted.rb +121 -102
- data/lib/attr_encrypted/adapters/active_record.rb +6 -4
- data/lib/attr_encrypted/version.rb +2 -2
- data/test/active_record_test.rb +9 -9
- data/test/attr_encrypted_test.rb +83 -7
- data/test/compatibility_test.rb +1 -1
- data/test/legacy_active_record_test.rb +1 -1
- data/test/legacy_compatibility_test.rb +1 -1
- data/test/test_helper.rb +7 -0
- metadata +34 -32
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f602391484e3437daae62ddb60596f0b4cbc83e0
|
4
|
+
data.tar.gz: 5e407d7e299a43380057a2f0fe816da3a6ad1fca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77b697d9e450d6baae65fb3ed339824b8bf730898296f172c2ae6b4e0bd7368add0da29c76596b9bbf71d298fccd038195f7ffb7d153ffaeaf2aabc7bfc60f9f
|
7
|
+
data.tar.gz: 211f1c52e7f0505d55eef59f06bb139f47fb1ae0158b39a643b5c7c5251865f13b871ab7b3194d44cd2fc6a128e86a5c6b9c8669bab6d2870a7914ed5dacb6c3
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.travis.yml
CHANGED
@@ -6,6 +6,8 @@ rvm:
|
|
6
6
|
- 2.1
|
7
7
|
- 2.2.2
|
8
8
|
- 2.3.0
|
9
|
+
- 2.4.0
|
10
|
+
- 2.5.0
|
9
11
|
- rbx
|
10
12
|
env:
|
11
13
|
- ACTIVERECORD=3.0.0
|
@@ -15,14 +17,41 @@ env:
|
|
15
17
|
- ACTIVERECORD=4.1.0
|
16
18
|
- ACTIVERECORD=4.2.0
|
17
19
|
- ACTIVERECORD=5.0.0
|
20
|
+
- ACTIVERECORD=5.1.1
|
18
21
|
matrix:
|
19
22
|
exclude:
|
20
23
|
- rvm: 2.0
|
21
24
|
env: ACTIVERECORD=5.0.0
|
25
|
+
- rvm: 2.0
|
26
|
+
env: ACTIVERECORD=5.1.1
|
22
27
|
- rvm: 2.1
|
23
28
|
env: ACTIVERECORD=5.0.0
|
29
|
+
- rvm: 2.1
|
30
|
+
env: ACTIVERECORD=5.1.1
|
31
|
+
- rvm: 2.4.0
|
32
|
+
env: ACTIVERECORD=3.0.0
|
33
|
+
- rvm: 2.4.0
|
34
|
+
env: ACTIVERECORD=3.1.0
|
35
|
+
- rvm: 2.4.0
|
36
|
+
env: ACTIVERECORD=3.2.0
|
37
|
+
- rvm: 2.4.0
|
38
|
+
env: ACTIVERECORD=4.0.0
|
39
|
+
- rvm: 2.4.0
|
40
|
+
env: ACTIVERECORD=4.1.0
|
41
|
+
- rvm: 2.5.0
|
42
|
+
env: ACTIVERECORD=3.0.0
|
43
|
+
- rvm: 2.5.0
|
44
|
+
env: ACTIVERECORD=3.1.0
|
45
|
+
- rvm: 2.5.0
|
46
|
+
env: ACTIVERECORD=3.2.0
|
47
|
+
- rvm: 2.5.0
|
48
|
+
env: ACTIVERECORD=4.0.0
|
49
|
+
- rvm: 2.5.0
|
50
|
+
env: ACTIVERECORD=4.1.0
|
24
51
|
- rvm: rbx
|
25
52
|
env: ACTIVERECORD=5.0.0
|
53
|
+
- rvm: rbx
|
54
|
+
env: ACTIVERECORD=5.1.1
|
26
55
|
allow_failures:
|
27
56
|
- rvm: rbx
|
28
57
|
fast_finish: true
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# attr_encrypted #
|
2
2
|
|
3
|
+
## 3.1.0 ##
|
4
|
+
* Added: Abitilty to encrypt empty values. (@tamird)
|
5
|
+
* Added: MIT license
|
6
|
+
* Added: MRI 2.5.x support (@saghaulor)
|
7
|
+
* Fixed: No long generate IV and salt if value is empty, unless :allow_empty_value options is passed. (@saghaulor)
|
8
|
+
* Fixed: Only generate IV and salt when :if and :unless options evaluate such that encryption should be performed. (@saghaulor)
|
9
|
+
* Fixed: Private methods are correctly evaluated as options. (@saghaulor)
|
10
|
+
* Fixed: Mark virtual attributes for Rails 5.x compatibility (@grosser)
|
11
|
+
* Fixed: Only check empty on strings, allows for encrypting non-string type objects
|
12
|
+
* Fixed: Fixed how accessors for db columns are defined in the ActiveRecord adapter, preventing premature definition. (@nagachika)
|
13
|
+
|
3
14
|
## 3.0.3 ##
|
4
15
|
* 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)
|
5
16
|
|
data/README.md
CHANGED
@@ -72,7 +72,7 @@ The `attr_encrypted` class method is also aliased as `attr_encryptor` to conform
|
|
72
72
|
|
73
73
|
### attr_encrypted with database persistence
|
74
74
|
|
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.
|
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 (initialization vector).
|
76
76
|
|
77
77
|
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
78
|
|
@@ -145,6 +145,7 @@ The following are the default options used by `attr_encrypted`:
|
|
145
145
|
decrypt_method: 'decrypt',
|
146
146
|
mode: :per_attribute_iv,
|
147
147
|
algorithm: 'aes-256-gcm',
|
148
|
+
allow_empty_value: false
|
148
149
|
```
|
149
150
|
|
150
151
|
All of the aforementioned options are explained in depth below.
|
@@ -195,7 +196,7 @@ If you don't like the `encrypted_#{attribute}` naming convention then you can sp
|
|
195
196
|
end
|
196
197
|
```
|
197
198
|
|
198
|
-
This would generate the following
|
199
|
+
This would generate the following attribute: `secret_email_crypted`.
|
199
200
|
|
200
201
|
|
201
202
|
### The `:key` option
|
@@ -296,7 +297,7 @@ You're probably going to be storing your encrypted attributes somehow (e.g. file
|
|
296
297
|
end
|
297
298
|
```
|
298
299
|
|
299
|
-
The default encoding is `m` (base64). You can change this by setting `encode: 'some encoding'`. See [`
|
300
|
+
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
301
|
|
301
302
|
|
302
303
|
### The `:marshal`, `:dump_method`, and `:load_method` options
|
@@ -311,6 +312,16 @@ You may want to encrypt objects other than strings (e.g. hashes, arrays, etc). I
|
|
311
312
|
|
312
313
|
You may also optionally specify `:marshaler`, `:dump_method`, and `:load_method` if you want to use something other than the default `Marshal` object.
|
313
314
|
|
315
|
+
### The `:allow_empty_value` option
|
316
|
+
|
317
|
+
You may want to encrypt empty strings or nil so as to not reveal which records are populated and which records are not.
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
class User
|
321
|
+
attr_encrypted :credentials, key: 'some secret key', marshal: true, allow_empty_value: true
|
322
|
+
end
|
323
|
+
```
|
324
|
+
|
314
325
|
|
315
326
|
## ORMs
|
316
327
|
|
@@ -400,7 +411,7 @@ It is recommended that you implement a strategy to insure that you do not mix th
|
|
400
411
|
|
401
412
|
```ruby
|
402
413
|
class User
|
403
|
-
attr_encrypted :ssn, key: :encryption_key, v2_gcm_iv:
|
414
|
+
attr_encrypted :ssn, key: :encryption_key, v2_gcm_iv: is_decrypting?(:ssn)
|
404
415
|
|
405
416
|
def is_decrypting?(attribute)
|
406
417
|
encrypted_attributes[attribute][:operation] == :decrypting
|
data/Rakefile
CHANGED
data/attr_encrypted.gemspec
CHANGED
@@ -17,6 +17,7 @@ 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
|
+
s.license = 'MIT'
|
20
21
|
|
21
22
|
s.has_rdoc = false
|
22
23
|
s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.rdoc']
|
@@ -41,6 +42,10 @@ Gem::Specification.new do |s|
|
|
41
42
|
s.add_development_dependency('rake')
|
42
43
|
s.add_development_dependency('minitest')
|
43
44
|
s.add_development_dependency('sequel')
|
45
|
+
if RUBY_VERSION < '2.1.0'
|
46
|
+
s.add_development_dependency('nokogiri', '< 1.7.0')
|
47
|
+
s.add_development_dependency('public_suffix', '< 3.0.0')
|
48
|
+
end
|
44
49
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE.to_sym == :jruby
|
45
50
|
s.add_development_dependency('activerecord-jdbcsqlite3-adapter')
|
46
51
|
s.add_development_dependency('jdbc-sqlite3', '< 3.8.7') # 3.8.7 is nice and broke
|
@@ -50,7 +55,7 @@ Gem::Specification.new do |s|
|
|
50
55
|
s.add_development_dependency('dm-sqlite-adapter')
|
51
56
|
s.add_development_dependency('simplecov')
|
52
57
|
s.add_development_dependency('simplecov-rcov')
|
53
|
-
s.add_development_dependency("codeclimate-test-reporter")
|
58
|
+
s.add_development_dependency("codeclimate-test-reporter", '<= 0.6.0')
|
54
59
|
|
55
60
|
s.cert_chain = ['certs/saghaulor.pem']
|
56
61
|
s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/
|
data/certs/saghaulor.pem
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
2
|
MIIDdDCCAlygAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMRIwEAYDVQQDDAlzYWdo
|
3
3
|
YXVsb3IxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
|
4
|
-
|
4
|
+
bTAeFw0xODAyMTIwMzMzMThaFw0xOTAyMTIwMzMzMThaMEAxEjAQBgNVBAMMCXNh
|
5
5
|
Z2hhdWxvcjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvOLqbSmj5txfw39a
|
7
|
+
Ki0g3BJWGrfGBiSRq9aThUGzoiaqyDo/m1WMQdgPioZG+P923okChEWFjhSymBQU
|
8
|
+
eMdys6JRPm5ortp5sh9gesOWoozqb8R55d8rr1V7pY533cCut53Kb1wiitjkfXjR
|
9
|
+
efT2HPh6nV6rYjGMJek/URaCNzsZo7HCkRsKdezP+BKr4V4wOka69tfJX5pcvFvR
|
10
|
+
iiqfaiP4RK12hYdsFnSVKiKP7SAFTFiYcohbL8TUW6ezQQqJCK0M6fu74EWVCnBS
|
11
|
+
gFVjj931BuD8qhuxMiB6uC6FKxemB5TRGBLzn7RcrOMAo2inMAopjkGeQJUAyVCm
|
12
|
+
J5US3wIDAQABo3kwdzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU
|
13
|
+
hJEuSZgvuuIhIsxQ/0pRQTBVzokwHgYDVR0RBBcwFYETc2FnaGF1bG9yQGdtYWls
|
14
14
|
LmNvbTAeBgNVHRIEFzAVgRNzYWdoYXVsb3JAZ21haWwuY29tMA0GCSqGSIb3DQEB
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
BQUAA4IBAQCsBS2cxqTmV4nXJEH/QbdgjVDAZbK6xf2gpM3vCRlYsy7Wz6GEoOpD
|
16
|
+
bzRkjxZwGNbhXShMUZwm6zahYQ/L1/HFztLoMBMkm8EIfPxH0PDrP4aWl0oyWxmU
|
17
|
+
OLm0/t9icSWRPPJ1tLJvuAaDdVpY5dEHd6VdnNJGQC5vHKRInt1kEyqEttIJ/xmJ
|
18
|
+
leSEFyMeoFsR+C/WPG9WSC+xN0eXqakCu6YUJoQzCn/7znv8WxpHEbeZjNIHq0qb
|
19
|
+
nbqZ/ZW1bwzj1T/NIbnMr37wqV29XwkI4+LbewMkb6/bDPYl0qZpAkCxKtGYCCJp
|
20
|
+
l6KPs9K/72yH00dxuAhiTXikTkcLXeQJ
|
21
21
|
-----END CERTIFICATE-----
|
@@ -0,0 +1 @@
|
|
1
|
+
6d84c64852c4bbc0926b92fe7a93295671a9e69cb2939b96fb1e4b5e8a5b33b6
|
@@ -0,0 +1 @@
|
|
1
|
+
0f960e8a2f63c747c273241f7395dcceb0dd8a6f79349bee453db741fc7ea5ceb4342d7d5908e540e3b5acea2216ff38bef8c743e6e7c8559bacb4a731ab27c4
|
data/lib/attr_encrypted.rb
CHANGED
@@ -16,90 +16,93 @@ module AttrEncrypted
|
|
16
16
|
#
|
17
17
|
# Options (any other options you specify are passed to the Encryptor's encrypt and decrypt methods)
|
18
18
|
#
|
19
|
-
# attribute:
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# prefix:
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# suffix:
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# key:
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
# encode:
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
# encode_iv:
|
58
|
-
|
59
|
-
# encode_salt:
|
60
|
-
#
|
61
|
-
# default_encoding:
|
62
|
-
#
|
63
|
-
# marshal:
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
# marshaler:
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# dump_method:
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# load_method:
|
75
|
-
#
|
76
|
-
#
|
77
|
-
# encryptor:
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# encrypt_method:
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# decrypt_method:
|
84
|
-
#
|
85
|
-
#
|
86
|
-
# if:
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
# unless:
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
# mode:
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
19
|
+
# attribute: The name of the referenced encrypted attribute. For example
|
20
|
+
# <tt>attr_accessor :email, attribute: :ee</tt> would generate an
|
21
|
+
# attribute named 'ee' to store the encrypted email. This is useful when defining
|
22
|
+
# one attribute to encrypt at a time or when the :prefix and :suffix options
|
23
|
+
# aren't enough.
|
24
|
+
# Defaults to nil.
|
25
|
+
#
|
26
|
+
# prefix: A prefix used to generate the name of the referenced encrypted attributes.
|
27
|
+
# For example <tt>attr_accessor :email, prefix: 'crypted_'</tt> would
|
28
|
+
# generate attributes named 'crypted_email' to store the encrypted
|
29
|
+
# email and password.
|
30
|
+
# Defaults to 'encrypted_'.
|
31
|
+
#
|
32
|
+
# suffix: A suffix used to generate the name of the referenced encrypted attributes.
|
33
|
+
# For example <tt>attr_accessor :email, prefix: '', suffix: '_encrypted'</tt>
|
34
|
+
# would generate attributes named 'email_encrypted' to store the
|
35
|
+
# encrypted email.
|
36
|
+
# Defaults to ''.
|
37
|
+
#
|
38
|
+
# key: The encryption key. This option may not be required if
|
39
|
+
# you're using a custom encryptor. If you pass a symbol
|
40
|
+
# representing an instance method then the :key option
|
41
|
+
# will be replaced with the result of the method before
|
42
|
+
# being passed to the encryptor. Objects that respond
|
43
|
+
# to :call are evaluated as well (including procs).
|
44
|
+
# Any other key types will be passed directly to the encryptor.
|
45
|
+
# Defaults to nil.
|
46
|
+
#
|
47
|
+
# encode: If set to true, attributes will be encoded as well as
|
48
|
+
# encrypted. This is useful if you're planning on storing
|
49
|
+
# the encrypted attributes in a database. The default
|
50
|
+
# encoding is 'm' (base64), however this can be overwritten
|
51
|
+
# by setting the :encode option to some other encoding
|
52
|
+
# string instead of just 'true'. See
|
53
|
+
# http://www.ruby-doc.org/core/classes/Array.html#M002245
|
54
|
+
# for more encoding directives.
|
55
|
+
# Defaults to false unless you're using it with ActiveRecord, DataMapper, or Sequel.
|
56
|
+
#
|
57
|
+
# encode_iv: Defaults to true.
|
58
|
+
|
59
|
+
# encode_salt: Defaults to true.
|
60
|
+
#
|
61
|
+
# default_encoding: Defaults to 'm' (base64).
|
62
|
+
#
|
63
|
+
# marshal: If set to true, attributes will be marshaled as well
|
64
|
+
# as encrypted. This is useful if you're planning on
|
65
|
+
# encrypting something other than a string.
|
66
|
+
# Defaults to false.
|
67
|
+
#
|
68
|
+
# marshaler: The object to use for marshaling.
|
69
|
+
# Defaults to Marshal.
|
70
|
+
#
|
71
|
+
# dump_method: The dump method name to call on the <tt>:marshaler</tt> object to.
|
72
|
+
# Defaults to 'dump'.
|
73
|
+
#
|
74
|
+
# load_method: The load method name to call on the <tt>:marshaler</tt> object.
|
75
|
+
# Defaults to 'load'.
|
76
|
+
#
|
77
|
+
# encryptor: The object to use for encrypting.
|
78
|
+
# Defaults to Encryptor.
|
79
|
+
#
|
80
|
+
# encrypt_method: The encrypt method name to call on the <tt>:encryptor</tt> object.
|
81
|
+
# Defaults to 'encrypt'.
|
82
|
+
#
|
83
|
+
# decrypt_method: The decrypt method name to call on the <tt>:encryptor</tt> object.
|
84
|
+
# Defaults to 'decrypt'.
|
85
|
+
#
|
86
|
+
# if: Attributes are only encrypted if this option evaluates
|
87
|
+
# to true. If you pass a symbol representing an instance
|
88
|
+
# method then the result of the method will be evaluated.
|
89
|
+
# Any objects that respond to <tt>:call</tt> are evaluated as well.
|
90
|
+
# Defaults to true.
|
91
|
+
#
|
92
|
+
# unless: Attributes are only encrypted if this option evaluates
|
93
|
+
# to false. If you pass a symbol representing an instance
|
94
|
+
# method then the result of the method will be evaluated.
|
95
|
+
# Any objects that respond to <tt>:call</tt> are evaluated as well.
|
96
|
+
# Defaults to false.
|
97
|
+
#
|
98
|
+
# mode: Selects encryption mode for attribute: choose <tt>:single_iv_and_salt</tt> for compatibility
|
99
|
+
# with the old attr_encrypted API: the IV is derived from the encryption key by the underlying Encryptor class; salt is not used.
|
100
|
+
# The <tt>:per_attribute_iv_and_salt</tt> mode uses a per-attribute IV and salt. The salt is used to derive a unique key per attribute.
|
101
|
+
# A <tt>:per_attribute_iv</default> mode derives a unique IV per attribute; salt is not used.
|
102
|
+
# Defaults to <tt>:per_attribute_iv</tt>.
|
103
|
+
#
|
104
|
+
# allow_empty_value: Attributes which have nil or empty string values will not be encrypted unless this option
|
105
|
+
# has a truthy value.
|
103
106
|
#
|
104
107
|
# You can specify your own default options
|
105
108
|
#
|
@@ -140,16 +143,19 @@ module AttrEncrypted
|
|
140
143
|
encrypted_attribute_name = (options[:attribute] ? options[:attribute] : [options[:prefix], attribute, options[:suffix]].join).to_sym
|
141
144
|
|
142
145
|
instance_methods_as_symbols = attribute_instance_methods_as_symbols
|
143
|
-
attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
|
144
|
-
attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")
|
145
146
|
|
146
|
-
|
147
|
-
|
148
|
-
|
147
|
+
if attribute_instance_methods_as_symbols_available?
|
148
|
+
attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
|
149
|
+
attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")
|
149
150
|
|
150
|
-
|
151
|
-
|
152
|
-
|
151
|
+
iv_name = "#{encrypted_attribute_name}_iv".to_sym
|
152
|
+
attr_reader iv_name unless instance_methods_as_symbols.include?(iv_name)
|
153
|
+
attr_writer iv_name unless instance_methods_as_symbols.include?(:"#{iv_name}=")
|
154
|
+
|
155
|
+
salt_name = "#{encrypted_attribute_name}_salt".to_sym
|
156
|
+
attr_reader salt_name unless instance_methods_as_symbols.include?(salt_name)
|
157
|
+
attr_writer salt_name unless instance_methods_as_symbols.include?(:"#{salt_name}=")
|
158
|
+
end
|
153
159
|
|
154
160
|
define_method(attribute) do
|
155
161
|
instance_variable_get("@#{attribute}") || instance_variable_set("@#{attribute}", decrypt(attribute, send(encrypted_attribute_name)))
|
@@ -197,6 +203,7 @@ module AttrEncrypted
|
|
197
203
|
decrypt_method: 'decrypt',
|
198
204
|
mode: :per_attribute_iv,
|
199
205
|
algorithm: 'aes-256-gcm',
|
206
|
+
allow_empty_value: false,
|
200
207
|
}
|
201
208
|
end
|
202
209
|
|
@@ -228,7 +235,7 @@ module AttrEncrypted
|
|
228
235
|
# email = User.decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
|
229
236
|
def decrypt(attribute, encrypted_value, options = {})
|
230
237
|
options = encrypted_attributes[attribute.to_sym].merge(options)
|
231
|
-
if options[:if] && !options[:unless] &&
|
238
|
+
if options[:if] && !options[:unless] && not_empty?(encrypted_value)
|
232
239
|
encrypted_value = encrypted_value.unpack(options[:encode]).first if options[:encode]
|
233
240
|
value = options[:encryptor].send(options[:decrypt_method], options.merge!(value: encrypted_value))
|
234
241
|
if options[:marshal]
|
@@ -254,7 +261,7 @@ module AttrEncrypted
|
|
254
261
|
# encrypted_email = User.encrypt(:email, 'test@example.com')
|
255
262
|
def encrypt(attribute, value, options = {})
|
256
263
|
options = encrypted_attributes[attribute.to_sym].merge(options)
|
257
|
-
if options[:if] && !options[:unless] &&
|
264
|
+
if options[:if] && !options[:unless] && (options[:allow_empty_value] || not_empty?(value))
|
258
265
|
value = options[:marshal] ? options[:marshaler].send(options[:dump_method], value) : value.to_s
|
259
266
|
encrypted_value = options[:encryptor].send(options[:encrypt_method], options.merge!(value: value))
|
260
267
|
encrypted_value = [encrypted_value].pack(options[:encode]) if options[:encode]
|
@@ -264,6 +271,10 @@ module AttrEncrypted
|
|
264
271
|
end
|
265
272
|
end
|
266
273
|
|
274
|
+
def not_empty?(value)
|
275
|
+
!value.nil? && !(value.is_a?(String) && value.empty?)
|
276
|
+
end
|
277
|
+
|
267
278
|
# Contains a hash of encrypted attributes with virtual attribute names as keys
|
268
279
|
# and their corresponding options as values
|
269
280
|
#
|
@@ -314,6 +325,7 @@ module AttrEncrypted
|
|
314
325
|
# @user.decrypt(:email, 'SOME_ENCRYPTED_EMAIL_STRING')
|
315
326
|
def decrypt(attribute, encrypted_value)
|
316
327
|
encrypted_attributes[attribute.to_sym][:operation] = :decrypting
|
328
|
+
encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(encrypted_value)
|
317
329
|
self.class.decrypt(attribute, encrypted_value, evaluated_attr_encrypted_options_for(attribute))
|
318
330
|
end
|
319
331
|
|
@@ -334,6 +346,7 @@ module AttrEncrypted
|
|
334
346
|
# @user.encrypt(:email, 'test@example.com')
|
335
347
|
def encrypt(attribute, value)
|
336
348
|
encrypted_attributes[attribute.to_sym][:operation] = :encrypting
|
349
|
+
encrypted_attributes[attribute.to_sym][:value_present] = self.class.not_empty?(value)
|
337
350
|
self.class.encrypt(attribute, value, evaluated_attr_encrypted_options_for(attribute))
|
338
351
|
end
|
339
352
|
|
@@ -357,12 +370,14 @@ module AttrEncrypted
|
|
357
370
|
evaluated_options[:attribute] = attribute_option_value
|
358
371
|
|
359
372
|
evaluated_options.tap do |options|
|
360
|
-
unless options[:
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
373
|
+
if options[:if] && !options[:unless] && options[:value_present] || options[:allow_empty_value]
|
374
|
+
unless options[:mode] == :single_iv_and_salt
|
375
|
+
load_iv_for_attribute(attribute, options)
|
376
|
+
end
|
377
|
+
|
378
|
+
if options[:mode] == :per_attribute_iv_and_salt
|
379
|
+
load_salt_for_attribute(attribute, options)
|
380
|
+
end
|
366
381
|
end
|
367
382
|
end
|
368
383
|
end
|
@@ -371,7 +386,7 @@ module AttrEncrypted
|
|
371
386
|
#
|
372
387
|
# If the option is not a symbol or proc then the original option is returned
|
373
388
|
def evaluate_attr_encrypted_option(option)
|
374
|
-
if option.is_a?(Symbol) && respond_to?(option)
|
389
|
+
if option.is_a?(Symbol) && respond_to?(option, true)
|
375
390
|
send(option)
|
376
391
|
elsif option.respond_to?(:call)
|
377
392
|
option.call(self)
|
@@ -408,7 +423,7 @@ module AttrEncrypted
|
|
408
423
|
encrypted_attribute_name = options[:attribute]
|
409
424
|
encode_salt = options[:encode_salt]
|
410
425
|
salt = options[:salt] || send("#{encrypted_attribute_name}_salt")
|
411
|
-
if
|
426
|
+
if options[:operation] == :encrypting
|
412
427
|
salt = SecureRandom.random_bytes
|
413
428
|
salt = prefix_and_encode_salt(salt, encode_salt) if encode_salt
|
414
429
|
send("#{encrypted_attribute_name}_salt=", salt)
|
@@ -436,6 +451,10 @@ module AttrEncrypted
|
|
436
451
|
instance_methods.collect { |method| method.to_sym }
|
437
452
|
end
|
438
453
|
|
454
|
+
def attribute_instance_methods_as_symbols_available?
|
455
|
+
true
|
456
|
+
end
|
457
|
+
|
439
458
|
end
|
440
459
|
|
441
460
|
|
@@ -51,6 +51,7 @@ if defined?(ActiveRecord::Base)
|
|
51
51
|
super
|
52
52
|
options = attrs.extract_options!
|
53
53
|
attr = attrs.pop
|
54
|
+
attribute attr if ::ActiveRecord::VERSION::STRING >= "5.1.0"
|
54
55
|
options.merge! encrypted_attributes[attr]
|
55
56
|
|
56
57
|
define_method("#{attr}_was") do
|
@@ -87,16 +88,17 @@ if defined?(ActiveRecord::Base)
|
|
87
88
|
# methods returned to let ActiveRecord define the accessor methods
|
88
89
|
# for the db columns
|
89
90
|
|
90
|
-
|
91
|
-
connected = ::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false
|
92
|
-
|
93
|
-
if connected && table_exists?
|
91
|
+
if connected? && table_exists?
|
94
92
|
columns_hash.keys.inject(super) {|instance_methods, column_name| instance_methods.concat [column_name.to_sym, :"#{column_name}="]}
|
95
93
|
else
|
96
94
|
super
|
97
95
|
end
|
98
96
|
end
|
99
97
|
|
98
|
+
def attribute_instance_methods_as_symbols_available?
|
99
|
+
connected? && table_exists?
|
100
|
+
end
|
101
|
+
|
100
102
|
# Allows you to use dynamic methods like <tt>find_by_email</tt> or <tt>scoped_by_email</tt> for
|
101
103
|
# encrypted attributes
|
102
104
|
#
|
data/test/active_record_test.rb
CHANGED
@@ -4,6 +4,7 @@ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:'
|
|
4
4
|
|
5
5
|
def create_tables
|
6
6
|
ActiveRecord::Schema.define(version: 1) do
|
7
|
+
self.verbose = false
|
7
8
|
create_table :people do |t|
|
8
9
|
t.string :encrypted_email
|
9
10
|
t.string :password
|
@@ -19,7 +20,7 @@ def create_tables
|
|
19
20
|
t.string :encrypted_password
|
20
21
|
t.string :encrypted_password_iv
|
21
22
|
t.string :encrypted_password_salt
|
22
|
-
t.
|
23
|
+
t.string :key
|
23
24
|
end
|
24
25
|
create_table :users do |t|
|
25
26
|
t.string :login
|
@@ -40,9 +41,6 @@ def create_tables
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
|
-
# The table needs to exist before defining the class
|
44
|
-
create_tables
|
45
|
-
|
46
44
|
ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
|
47
45
|
|
48
46
|
if ::ActiveRecord::VERSION::STRING > "4.0"
|
@@ -81,7 +79,7 @@ class PersonWithProcMode < Person
|
|
81
79
|
end
|
82
80
|
|
83
81
|
class Account < ActiveRecord::Base
|
84
|
-
ACCOUNT_ENCRYPTION_KEY = SecureRandom.
|
82
|
+
ACCOUNT_ENCRYPTION_KEY = SecureRandom.urlsafe_base64(24)
|
85
83
|
attr_encrypted :password, key: :password_encryption_key
|
86
84
|
|
87
85
|
def encrypting?(attr)
|
@@ -128,7 +126,7 @@ end
|
|
128
126
|
class ActiveRecordTest < Minitest::Test
|
129
127
|
|
130
128
|
def setup
|
131
|
-
|
129
|
+
drop_all_tables
|
132
130
|
create_tables
|
133
131
|
end
|
134
132
|
|
@@ -206,7 +204,7 @@ class ActiveRecordTest < Minitest::Test
|
|
206
204
|
|
207
205
|
def test_attribute_was_works_when_options_for_old_encrypted_value_are_different_than_options_for_new_encrypted_value
|
208
206
|
pw = 'password'
|
209
|
-
crypto_key = SecureRandom.
|
207
|
+
crypto_key = SecureRandom.urlsafe_base64(24)
|
210
208
|
old_iv = SecureRandom.random_bytes(12)
|
211
209
|
account = Account.create
|
212
210
|
encrypted_value = Encryptor.encrypt(value: pw, iv: old_iv, key: crypto_key)
|
@@ -332,7 +330,9 @@ class ActiveRecordTest < Minitest::Test
|
|
332
330
|
def test_should_evaluate_proc_based_mode
|
333
331
|
street = '123 Elm'
|
334
332
|
zipcode = '12345'
|
335
|
-
address = Address.
|
336
|
-
|
333
|
+
address = Address.create(street: street, zipcode: zipcode, mode: :single_iv_and_salt)
|
334
|
+
address.reload
|
335
|
+
refute_equal address.encrypted_zipcode, zipcode
|
336
|
+
assert_equal address.zipcode, zipcode
|
337
337
|
end
|
338
338
|
end
|
data/test/attr_encrypted_test.rb
CHANGED
@@ -23,11 +23,12 @@ class User
|
|
23
23
|
attr_encrypted :with_encoding, :key => SECRET_KEY, :encode => true
|
24
24
|
attr_encrypted :with_custom_encoding, :key => SECRET_KEY, :encode => 'm'
|
25
25
|
attr_encrypted :with_marshaling, :key => SECRET_KEY, :marshal => true
|
26
|
-
attr_encrypted :with_true_if, :key => SECRET_KEY, :if => true
|
27
|
-
attr_encrypted :with_false_if, :key => SECRET_KEY, :if => false
|
28
|
-
attr_encrypted :with_true_unless, :key => SECRET_KEY, :unless => true
|
29
|
-
attr_encrypted :with_false_unless, :key => SECRET_KEY, :unless => false
|
26
|
+
attr_encrypted :with_true_if, :key => SECRET_KEY, :if => true, mode: :per_attribute_iv_and_salt
|
27
|
+
attr_encrypted :with_false_if, :key => SECRET_KEY, :if => false, mode: :per_attribute_iv_and_salt
|
28
|
+
attr_encrypted :with_true_unless, :key => SECRET_KEY, :unless => true, mode: :per_attribute_iv_and_salt
|
29
|
+
attr_encrypted :with_false_unless, :key => SECRET_KEY, :unless => false, mode: :per_attribute_iv_and_salt
|
30
30
|
attr_encrypted :with_if_changed, :key => SECRET_KEY, :if => :should_encrypt
|
31
|
+
attr_encrypted :with_allow_empty_value, key: SECRET_KEY, allow_empty_value: true, marshal: true
|
31
32
|
|
32
33
|
attr_encryptor :aliased, :key => SECRET_KEY
|
33
34
|
|
@@ -40,6 +41,7 @@ class User
|
|
40
41
|
self.should_encrypt = true
|
41
42
|
end
|
42
43
|
|
44
|
+
private
|
43
45
|
def secret_key
|
44
46
|
SECRET_KEY
|
45
47
|
end
|
@@ -114,7 +116,7 @@ class AttrEncryptedTest < Minitest::Test
|
|
114
116
|
assert_nil User.encrypt_email(nil, iv: @iv)
|
115
117
|
end
|
116
118
|
|
117
|
-
def
|
119
|
+
def test_should_not_encrypt_empty_string_by_default
|
118
120
|
assert_equal '', User.encrypt_email('', iv: @iv)
|
119
121
|
end
|
120
122
|
|
@@ -150,9 +152,14 @@ class AttrEncryptedTest < Minitest::Test
|
|
150
152
|
def test_should_decrypt_email_when_reading
|
151
153
|
@user = User.new
|
152
154
|
assert_nil @user.email
|
153
|
-
|
154
|
-
|
155
|
+
options = @user.encrypted_attributes[:email]
|
156
|
+
iv = @user.send(:generate_iv, options[:algorithm])
|
157
|
+
encoded_iv = [iv].pack(options[:encode_iv])
|
158
|
+
salt = SecureRandom.random_bytes
|
159
|
+
encoded_salt = @user.send(:prefix_and_encode_salt, salt, options[:encode_salt])
|
155
160
|
@user.encrypted_email = User.encrypt_email('test@example.com', iv: iv, salt: salt)
|
161
|
+
@user.encrypted_email_iv = encoded_iv
|
162
|
+
@user.encrypted_email_salt = encoded_salt
|
156
163
|
assert_equal 'test@example.com', @user.email
|
157
164
|
end
|
158
165
|
|
@@ -282,6 +289,18 @@ class AttrEncryptedTest < Minitest::Test
|
|
282
289
|
assert_equal 'testing', @user.encrypted_with_true_unless
|
283
290
|
end
|
284
291
|
|
292
|
+
def test_should_encrypt_empty_with_truthy_allow_empty_value_option
|
293
|
+
@user = User.new
|
294
|
+
assert_nil @user.encrypted_with_allow_empty_value
|
295
|
+
@user.with_allow_empty_value = ''
|
296
|
+
refute_nil @user.encrypted_with_allow_empty_value
|
297
|
+
assert_equal '', @user.with_allow_empty_value
|
298
|
+
@user = User.new
|
299
|
+
@user.with_allow_empty_value = nil
|
300
|
+
refute_nil @user.encrypted_with_allow_empty_value
|
301
|
+
assert_nil @user.with_allow_empty_value
|
302
|
+
end
|
303
|
+
|
285
304
|
def test_should_work_with_aliased_attr_encryptor
|
286
305
|
assert User.encrypted_attributes.include?(:aliased)
|
287
306
|
end
|
@@ -390,4 +409,61 @@ class AttrEncryptedTest < Minitest::Test
|
|
390
409
|
user.email = 'revised_value@test.com'
|
391
410
|
refute_equal original_iv, user.encrypted_email_iv
|
392
411
|
end
|
412
|
+
|
413
|
+
def test_should_not_generate_iv_for_attribute_when_if_option_is_false
|
414
|
+
user = User.new
|
415
|
+
user.with_false_if = 'derp'
|
416
|
+
assert_nil user.encrypted_with_false_if_iv
|
417
|
+
end
|
418
|
+
|
419
|
+
def test_should_generate_iv_for_attribute_when_if_option_is_true
|
420
|
+
user = User.new
|
421
|
+
user.with_true_if = 'derp'
|
422
|
+
refute_nil user.encrypted_with_true_if_iv
|
423
|
+
|
424
|
+
user.with_true_if = Object.new
|
425
|
+
refute_nil user.encrypted_with_true_if_iv
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_should_not_generate_salt_for_attribute_when_if_option_is_false
|
429
|
+
user = User.new
|
430
|
+
user.with_false_if = 'derp'
|
431
|
+
assert_nil user.encrypted_with_false_if_salt
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_should_generate_salt_for_attribute_when_if_option_is_true
|
435
|
+
user = User.new
|
436
|
+
user.with_true_if = 'derp'
|
437
|
+
refute_nil user.encrypted_with_true_if_salt
|
438
|
+
end
|
439
|
+
|
440
|
+
def test_should_generate_iv_for_attribute_when_unless_option_is_false
|
441
|
+
user = User.new
|
442
|
+
user.with_false_unless = 'derp'
|
443
|
+
refute_nil user.encrypted_with_false_unless_iv
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_should_not_generate_iv_for_attribute_when_unless_option_is_true
|
447
|
+
user = User.new
|
448
|
+
user.with_true_unless = 'derp'
|
449
|
+
assert_nil user.encrypted_with_true_unless_iv
|
450
|
+
end
|
451
|
+
|
452
|
+
def test_should_generate_salt_for_attribute_when_unless_option_is_false
|
453
|
+
user = User.new
|
454
|
+
user.with_false_unless = 'derp'
|
455
|
+
refute_nil user.encrypted_with_false_unless_salt
|
456
|
+
end
|
457
|
+
|
458
|
+
def test_should_not_generate_salt_for_attribute_when_unless_option_is_true
|
459
|
+
user = User.new
|
460
|
+
user.with_true_unless = 'derp'
|
461
|
+
assert_nil user.encrypted_with_true_unless_salt
|
462
|
+
end
|
463
|
+
|
464
|
+
def test_should_not_by_default_generate_iv_when_attribute_is_empty
|
465
|
+
user = User.new
|
466
|
+
user.with_true_if = nil
|
467
|
+
assert_nil user.encrypted_with_true_if_iv
|
468
|
+
end
|
393
469
|
end
|
data/test/compatibility_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -27,6 +27,7 @@ require 'active_record'
|
|
27
27
|
require 'data_mapper'
|
28
28
|
require 'digest/sha2'
|
29
29
|
require 'sequel'
|
30
|
+
ActiveSupport::Deprecation.behavior = :raise
|
30
31
|
|
31
32
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
32
33
|
$:.unshift(File.dirname(__FILE__))
|
@@ -49,3 +50,9 @@ SECRET_KEY = SecureRandom.random_bytes(32)
|
|
49
50
|
def base64_encoding_regex
|
50
51
|
/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$/
|
51
52
|
end
|
53
|
+
|
54
|
+
def drop_all_tables
|
55
|
+
connection = ActiveRecord::Base.connection
|
56
|
+
tables = (ActiveRecord::VERSION::MAJOR >= 5 ? connection.data_sources : connection.tables)
|
57
|
+
tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
|
58
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attr_encrypted
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Huber
|
@@ -15,25 +15,25 @@ cert_chain:
|
|
15
15
|
-----BEGIN CERTIFICATE-----
|
16
16
|
MIIDdDCCAlygAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMRIwEAYDVQQDDAlzYWdo
|
17
17
|
YXVsb3IxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
|
18
|
-
|
18
|
+
bTAeFw0xODAyMTIwMzMzMThaFw0xOTAyMTIwMzMzMThaMEAxEjAQBgNVBAMMCXNh
|
19
19
|
Z2hhdWxvcjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvOLqbSmj5txfw39a
|
21
|
+
Ki0g3BJWGrfGBiSRq9aThUGzoiaqyDo/m1WMQdgPioZG+P923okChEWFjhSymBQU
|
22
|
+
eMdys6JRPm5ortp5sh9gesOWoozqb8R55d8rr1V7pY533cCut53Kb1wiitjkfXjR
|
23
|
+
efT2HPh6nV6rYjGMJek/URaCNzsZo7HCkRsKdezP+BKr4V4wOka69tfJX5pcvFvR
|
24
|
+
iiqfaiP4RK12hYdsFnSVKiKP7SAFTFiYcohbL8TUW6ezQQqJCK0M6fu74EWVCnBS
|
25
|
+
gFVjj931BuD8qhuxMiB6uC6FKxemB5TRGBLzn7RcrOMAo2inMAopjkGeQJUAyVCm
|
26
|
+
J5US3wIDAQABo3kwdzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU
|
27
|
+
hJEuSZgvuuIhIsxQ/0pRQTBVzokwHgYDVR0RBBcwFYETc2FnaGF1bG9yQGdtYWls
|
28
28
|
LmNvbTAeBgNVHRIEFzAVgRNzYWdoYXVsb3JAZ21haWwuY29tMA0GCSqGSIb3DQEB
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
BQUAA4IBAQCsBS2cxqTmV4nXJEH/QbdgjVDAZbK6xf2gpM3vCRlYsy7Wz6GEoOpD
|
30
|
+
bzRkjxZwGNbhXShMUZwm6zahYQ/L1/HFztLoMBMkm8EIfPxH0PDrP4aWl0oyWxmU
|
31
|
+
OLm0/t9icSWRPPJ1tLJvuAaDdVpY5dEHd6VdnNJGQC5vHKRInt1kEyqEttIJ/xmJ
|
32
|
+
leSEFyMeoFsR+C/WPG9WSC+xN0eXqakCu6YUJoQzCn/7znv8WxpHEbeZjNIHq0qb
|
33
|
+
nbqZ/ZW1bwzj1T/NIbnMr37wqV29XwkI4+LbewMkb6/bDPYl0qZpAkCxKtGYCCJp
|
34
|
+
l6KPs9K/72yH00dxuAhiTXikTkcLXeQJ
|
35
35
|
-----END CERTIFICATE-----
|
36
|
-
date:
|
36
|
+
date: 2018-02-11 00:00:00.000000000 Z
|
37
37
|
dependencies:
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: encryptor
|
@@ -53,30 +53,30 @@ dependencies:
|
|
53
53
|
name: activerecord
|
54
54
|
requirement: !ruby/object:Gem::Requirement
|
55
55
|
requirements:
|
56
|
-
- - "
|
56
|
+
- - "~>"
|
57
57
|
- !ruby/object:Gem::Version
|
58
|
-
version:
|
58
|
+
version: 4.1.16
|
59
59
|
type: :development
|
60
60
|
prerelease: false
|
61
61
|
version_requirements: !ruby/object:Gem::Requirement
|
62
62
|
requirements:
|
63
|
-
- - "
|
63
|
+
- - "~>"
|
64
64
|
- !ruby/object:Gem::Version
|
65
|
-
version:
|
65
|
+
version: 4.1.16
|
66
66
|
- !ruby/object:Gem::Dependency
|
67
67
|
name: actionpack
|
68
68
|
requirement: !ruby/object:Gem::Requirement
|
69
69
|
requirements:
|
70
|
-
- - "
|
70
|
+
- - "~>"
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version:
|
72
|
+
version: 4.1.16
|
73
73
|
type: :development
|
74
74
|
prerelease: false
|
75
75
|
version_requirements: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
|
-
- - "
|
77
|
+
- - "~>"
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version:
|
79
|
+
version: 4.1.16
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: datamapper
|
82
82
|
requirement: !ruby/object:Gem::Requirement
|
@@ -193,16 +193,16 @@ dependencies:
|
|
193
193
|
name: codeclimate-test-reporter
|
194
194
|
requirement: !ruby/object:Gem::Requirement
|
195
195
|
requirements:
|
196
|
-
- - "
|
196
|
+
- - "<="
|
197
197
|
- !ruby/object:Gem::Version
|
198
|
-
version:
|
198
|
+
version: 0.6.0
|
199
199
|
type: :development
|
200
200
|
prerelease: false
|
201
201
|
version_requirements: !ruby/object:Gem::Requirement
|
202
202
|
requirements:
|
203
|
-
- - "
|
203
|
+
- - "<="
|
204
204
|
- !ruby/object:Gem::Version
|
205
|
-
version:
|
205
|
+
version: 0.6.0
|
206
206
|
description: Generates attr_accessors that encrypt and decrypt attributes transparently
|
207
207
|
email:
|
208
208
|
- seah@shuber.io
|
@@ -228,6 +228,8 @@ files:
|
|
228
228
|
- checksum/attr_encrypted-3.0.1.gem.sha512
|
229
229
|
- checksum/attr_encrypted-3.0.2.gem.sha256
|
230
230
|
- checksum/attr_encrypted-3.0.2.gem.sha512
|
231
|
+
- checksum/attr_encrypted-3.0.3.gem.sha256
|
232
|
+
- checksum/attr_encrypted-3.0.3.gem.sha512
|
231
233
|
- lib/attr_encrypted.rb
|
232
234
|
- lib/attr_encrypted/adapters/active_record.rb
|
233
235
|
- lib/attr_encrypted/adapters/data_mapper.rb
|
@@ -246,7 +248,8 @@ files:
|
|
246
248
|
- test/sequel_test.rb
|
247
249
|
- test/test_helper.rb
|
248
250
|
homepage: http://github.com/attr-encrypted/attr_encrypted
|
249
|
-
licenses:
|
251
|
+
licenses:
|
252
|
+
- MIT
|
250
253
|
metadata: {}
|
251
254
|
post_install_message: |2+
|
252
255
|
|
@@ -280,7 +283,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
280
283
|
version: '0'
|
281
284
|
requirements: []
|
282
285
|
rubyforge_project:
|
283
|
-
rubygems_version: 2.
|
286
|
+
rubygems_version: 2.6.13
|
284
287
|
signing_key:
|
285
288
|
specification_version: 4
|
286
289
|
summary: Encrypt and decrypt attributes
|
@@ -297,4 +300,3 @@ test_files:
|
|
297
300
|
- test/run.sh
|
298
301
|
- test/sequel_test.rb
|
299
302
|
- test/test_helper.rb
|
300
|
-
has_rdoc: false
|
metadata.gz.sig
CHANGED
Binary file
|