attr_encrypted 3.0.3 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|