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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5c1a2bcf5e2b7fc8937e96cb0fcd99926bd98d1e
4
- data.tar.gz: 40112aef07bda5ba8145b2fb634a9bdbfea34d7a
3
+ metadata.gz: f602391484e3437daae62ddb60596f0b4cbc83e0
4
+ data.tar.gz: 5e407d7e299a43380057a2f0fe816da3a6ad1fca
5
5
  SHA512:
6
- metadata.gz: cbb4fb1d4fa7e22f791139ab1b9a96324cbb8e07f7e8472561a3dd0ce1fcb0a7c048c0ba413b5bccb876dade09f9528ccc7d23caa4378de3da8ef2c540ba76ad
7
- data.tar.gz: ef6b487235f2f92ccdf73de3c806b3b3f9161c2ebcd78b2102e1975edc3150cda28a7b458136a051100e939a271b2e92ca690cd38360ec5c43c9c33db22dc1f4
6
+ metadata.gz: 77b697d9e450d6baae65fb3ed339824b8bf730898296f172c2ae6b4e0bd7368add0da29c76596b9bbf71d298fccd038195f7ffb7d153ffaeaf2aabc7bfc60f9f
7
+ data.tar.gz: 211f1c52e7f0505d55eef59f06bb139f47fb1ae0158b39a643b5c7c5251865f13b871ab7b3194d44cd2fc6a128e86a5c6b9c8669bab6d2870a7914ed5dacb6c3
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -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
@@ -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 attributes: `secret_email_crypted`, `secret_credit_card_crypted`, and `secret_ssn_crypted`.
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 [`Arrary#pack`](http://ruby-doc.org/core-2.3.0/Array.html#method-i-pack) for more encoding options.
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: :is_decrypting?(:ssn)
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
@@ -6,6 +6,7 @@ desc 'Test the attr_encrypted gem.'
6
6
  Rake::TestTask.new(:test) do |t|
7
7
  t.libs << 'lib'
8
8
  t.pattern = 'test/**/*_test.rb'
9
+ t.warning = false
9
10
  t.verbose = true
10
11
  end
11
12
 
@@ -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/
@@ -1,21 +1,21 @@
1
1
  -----BEGIN CERTIFICATE-----
2
2
  MIIDdDCCAlygAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMRIwEAYDVQQDDAlzYWdo
3
3
  YXVsb3IxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
4
- bTAeFw0xNjAxMTEyMjQyMDFaFw0xNzAxMTAyMjQyMDFaMEAxEjAQBgNVBAMMCXNh
4
+ bTAeFw0xODAyMTIwMzMzMThaFw0xOTAyMTIwMzMzMThaMEAxEjAQBgNVBAMMCXNh
5
5
  Z2hhdWxvcjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
6
- Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0xdQYk2GwCpQ1n/
7
- n2mPVYHLYqU5TAn/82t5kbqBUWjbcj8tHAi41tJ19+fT/hH0dog8JHvho1zmOr71
8
- ZIqreJQo60TqP6oE9a5HncUpjqbRp7tOmHo9E+mOW1yT4NiXqFf1YINExQKy2XND
9
- WPQ+T50ZNUsGMfHFWB4NAymejRWXlOEY3bvKW0UHFeNmouP5he51TjoP8uCc9536
10
- 4AIWVP/zzzjwrFtC7av7nRw4Y+gX2bQjrkK2k2JS0ejiGzKBIEMJejcI2B+t79zT
11
- kUQq9SFwp2BrKSIy+4kh4CiF20RT/Hfc1MbvTxSIl/bbIxCYEOhmtHExHi0CoCWs
12
- YCGCXQIDAQABo3kwdzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU
13
- SCpVzSBvYbO6B3oT3n3RCZmurG8wHgYDVR0RBBcwFYETc2FnaGF1bG9yQGdtYWls
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
- BQUAA4IBAQAeiGdC3e0WiZpm0cF/b7JC6hJYXC9Yv9VsRAWD9ROsLjFKwOhmonnc
16
- +l/QrmoTjMakYXBCai/Ca3L+k5eRrKilgyITILsmmFxK8sqPJXUw2Jmwk/dAky6x
17
- hHKVZAofT1OrOOPJ2USoZyhR/VI8epLaD5wUmkVDNqtZWviW+dtRa55aPYjRw5Pj
18
- wuj9nybhZr+BbEbmZE//2nbfkM4hCuMtxxxilPrJ22aYNmeWU0wsPpDyhPYxOUgU
19
- ZjeLmnSDiwL6doiP5IiwALH/dcHU67ck3NGf6XyqNwQrrmtPY0mv1WVVL4Uh+vYE
20
- kHoFzE2no0BfBg78Re8fY69P5yES5ncC
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
@@ -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: 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>.
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
- iv_name = "#{encrypted_attribute_name}_iv".to_sym
147
- attr_reader iv_name unless instance_methods_as_symbols.include?(iv_name)
148
- attr_writer iv_name unless instance_methods_as_symbols.include?(:"#{iv_name}=")
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
- salt_name = "#{encrypted_attribute_name}_salt".to_sym
151
- attr_reader salt_name unless instance_methods_as_symbols.include?(salt_name)
152
- attr_writer salt_name unless instance_methods_as_symbols.include?(:"#{salt_name}=")
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] && !encrypted_value.nil? && !(encrypted_value.is_a?(String) && encrypted_value.empty?)
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] && !value.nil? && !(value.is_a?(String) && value.empty?)
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[:mode] == :single_iv_and_salt
361
- load_iv_for_attribute(attribute, options)
362
- end
363
-
364
- if options[:mode] == :per_attribute_iv_and_salt
365
- load_salt_for_attribute(attribute, options)
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 (salt == nil)
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
- # Use with_connection so the connection doesn't stay pinned to the thread.
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
  #
@@ -2,8 +2,8 @@ module AttrEncrypted
2
2
  # Contains information about this gem's version
3
3
  module Version
4
4
  MAJOR = 3
5
- MINOR = 0
6
- PATCH = 3
5
+ MINOR = 1
6
+ PATCH = 0
7
7
 
8
8
  # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
9
9
  #
@@ -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.binary :key
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.base64(32)
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
- ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
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.base64(32)
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.new(street: street, zipcode: zipcode, mode: :single_iv_and_salt)
336
- assert_nil address.encrypted_zipcode_iv
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
@@ -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 test_should_not_encrypt_empty_string
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
- iv = @user.encrypted_email_iv.unpack('m').first
154
- salt = @user.encrypted_email_salt[1..-1].unpack('m').first
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
@@ -41,7 +41,7 @@ class CompatibilityTest < Minitest::Test
41
41
  end
42
42
 
43
43
  def setup
44
- ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
44
+ drop_all_tables
45
45
  create_tables
46
46
  end
47
47
 
@@ -50,7 +50,7 @@ end
50
50
  class LegacyActiveRecordTest < Minitest::Test
51
51
 
52
52
  def setup
53
- ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
53
+ drop_all_tables
54
54
  create_people_table
55
55
  end
56
56
 
@@ -41,7 +41,7 @@ class LegacyCompatibilityTest < Minitest::Test
41
41
  end
42
42
 
43
43
  def setup
44
- ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
44
+ drop_all_tables
45
45
  create_tables
46
46
  end
47
47
 
@@ -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.3
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
- bTAeFw0xNjAxMTEyMjQyMDFaFw0xNzAxMTAyMjQyMDFaMEAxEjAQBgNVBAMMCXNh
18
+ bTAeFw0xODAyMTIwMzMzMThaFw0xOTAyMTIwMzMzMThaMEAxEjAQBgNVBAMMCXNh
19
19
  Z2hhdWxvcjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
20
- Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0xdQYk2GwCpQ1n/
21
- n2mPVYHLYqU5TAn/82t5kbqBUWjbcj8tHAi41tJ19+fT/hH0dog8JHvho1zmOr71
22
- ZIqreJQo60TqP6oE9a5HncUpjqbRp7tOmHo9E+mOW1yT4NiXqFf1YINExQKy2XND
23
- WPQ+T50ZNUsGMfHFWB4NAymejRWXlOEY3bvKW0UHFeNmouP5he51TjoP8uCc9536
24
- 4AIWVP/zzzjwrFtC7av7nRw4Y+gX2bQjrkK2k2JS0ejiGzKBIEMJejcI2B+t79zT
25
- kUQq9SFwp2BrKSIy+4kh4CiF20RT/Hfc1MbvTxSIl/bbIxCYEOhmtHExHi0CoCWs
26
- YCGCXQIDAQABo3kwdzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU
27
- SCpVzSBvYbO6B3oT3n3RCZmurG8wHgYDVR0RBBcwFYETc2FnaGF1bG9yQGdtYWls
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
- BQUAA4IBAQAeiGdC3e0WiZpm0cF/b7JC6hJYXC9Yv9VsRAWD9ROsLjFKwOhmonnc
30
- +l/QrmoTjMakYXBCai/Ca3L+k5eRrKilgyITILsmmFxK8sqPJXUw2Jmwk/dAky6x
31
- hHKVZAofT1OrOOPJ2USoZyhR/VI8epLaD5wUmkVDNqtZWviW+dtRa55aPYjRw5Pj
32
- wuj9nybhZr+BbEbmZE//2nbfkM4hCuMtxxxilPrJ22aYNmeWU0wsPpDyhPYxOUgU
33
- ZjeLmnSDiwL6doiP5IiwALH/dcHU67ck3NGf6XyqNwQrrmtPY0mv1WVVL4Uh+vYE
34
- kHoFzE2no0BfBg78Re8fY69P5yES5ncC
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: 2016-07-22 00:00:00.000000000 Z
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: 2.0.0
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: 2.0.0
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: 2.0.0
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: 2.0.0
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: '0'
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: '0'
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.4.5.1
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