lockbox 0.6.0 → 0.6.5
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
- data/CHANGELOG.md +26 -0
- data/LICENSE.txt +1 -1
- data/README.md +40 -25
- data/lib/generators/lockbox/audits_generator.rb +11 -3
- data/lib/lockbox.rb +11 -2
- data/lib/lockbox/carrier_wave_extensions.rb +14 -3
- data/lib/lockbox/model.rb +72 -7
- data/lib/lockbox/railtie.rb +13 -1
- data/lib/lockbox/version.rb +1 -1
- metadata +5 -187
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c45d2348a69188c159cef722e1bcf20cbb47091d41a18dea9aad623479138f9b
|
4
|
+
data.tar.gz: 62aa904c4dadd24e8fa727f8d7d8e966d2f9aac8494c05185ecee6bb1129de5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f65d019fd987015f246fa3fb901ff23047663cce1a09edeca6e1a69e39e06b6442ec74a12057bc1850704414bfd8ca283da55a1990fa130119faba9df01e136f
|
7
|
+
data.tar.gz: 98c7b76529683742621eea3e9c16b6cd1666b125720da58e1f3babb79d2e6b717e47de97b7593425d3ae106553d896d720e75a43165a88cd79a92a255a65a223
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
## 0.6.5 (2021-07-07)
|
2
|
+
|
3
|
+
- Fixed issue with `pluck` extension not loading in some cases
|
4
|
+
|
5
|
+
## 0.6.4 (2021-04-05)
|
6
|
+
|
7
|
+
- Fixed in place changes in callbacks
|
8
|
+
- Fixed `[]` method for encrypted attributes
|
9
|
+
|
10
|
+
## 0.6.3 (2021-03-30)
|
11
|
+
|
12
|
+
- Fixed empty arrays and hashes
|
13
|
+
- Fixed content type for CarrierWave 2.2.1
|
14
|
+
|
15
|
+
## 0.6.2 (2021-02-08)
|
16
|
+
|
17
|
+
- Added `inet` type
|
18
|
+
- Fixed error when `lockbox` key in Rails credentials has a string value
|
19
|
+
- Fixed deprecation warning with Active Record 6.1
|
20
|
+
|
21
|
+
## 0.6.1 (2020-12-03)
|
22
|
+
|
23
|
+
- Added integration with Rails credentials
|
24
|
+
- Fixed in place changes for Active Record 6.1
|
25
|
+
- Fixed error with `content_type` method for CarrierWave < 2
|
26
|
+
|
1
27
|
## 0.6.0 (2020-12-03)
|
2
28
|
|
3
29
|
- Added `encrypted` flag to Active Storage metadata
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -27,7 +27,7 @@ Generate a key
|
|
27
27
|
Lockbox.generate_key
|
28
28
|
```
|
29
29
|
|
30
|
-
Store the key with your other secrets. This is typically Rails credentials or an environment variable ([dotenv](https://github.com/bkeepers/dotenv) is great for this). Be sure to use different keys in development and production.
|
30
|
+
Store the key with your other secrets. This is typically Rails credentials or an environment variable ([dotenv](https://github.com/bkeepers/dotenv) is great for this). Be sure to use different keys in development and production.
|
31
31
|
|
32
32
|
Set the following environment variable with your key (you can use this one in development)
|
33
33
|
|
@@ -35,10 +35,17 @@ Set the following environment variable with your key (you can use this one in de
|
|
35
35
|
LOCKBOX_MASTER_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
36
36
|
```
|
37
37
|
|
38
|
+
or add it to your credentials for each environment (`rails credentials:edit --environment <env>` for Rails 6+)
|
39
|
+
|
40
|
+
```yml
|
41
|
+
lockbox:
|
42
|
+
master_key: "0000000000000000000000000000000000000000000000000000000000000000"
|
43
|
+
```
|
44
|
+
|
38
45
|
or create `config/initializers/lockbox.rb` with something like
|
39
46
|
|
40
47
|
```ruby
|
41
|
-
Lockbox.master_key = Rails.application.credentials.
|
48
|
+
Lockbox.master_key = Rails.application.credentials.lockbox[:master_key]
|
42
49
|
```
|
43
50
|
|
44
51
|
Then follow the instructions below for the data you want to encrypt.
|
@@ -65,7 +72,7 @@ Then follow the instructions below for the data you want to encrypt.
|
|
65
72
|
Create a migration with:
|
66
73
|
|
67
74
|
```ruby
|
68
|
-
class AddEmailCiphertextToUsers < ActiveRecord::Migration[6.
|
75
|
+
class AddEmailCiphertextToUsers < ActiveRecord::Migration[6.1]
|
69
76
|
def change
|
70
77
|
add_column :users, :email_ciphertext, :text
|
71
78
|
end
|
@@ -114,6 +121,7 @@ class User < ApplicationRecord
|
|
114
121
|
encrypts :properties, type: :json
|
115
122
|
encrypts :settings, type: :hash
|
116
123
|
encrypts :messages, type: :array
|
124
|
+
encrypts :ip, type: :inet
|
117
125
|
end
|
118
126
|
```
|
119
127
|
|
@@ -240,7 +248,7 @@ User.decrypt_email_ciphertext(user.email_ciphertext)
|
|
240
248
|
Create a migration with:
|
241
249
|
|
242
250
|
```ruby
|
243
|
-
class AddBodyCiphertextToRichTexts < ActiveRecord::Migration[6.
|
251
|
+
class AddBodyCiphertextToRichTexts < ActiveRecord::Migration[6.1]
|
244
252
|
def change
|
245
253
|
add_column :action_text_rich_texts, :body_ciphertext, :text
|
246
254
|
end
|
@@ -328,9 +336,7 @@ def license
|
|
328
336
|
end
|
329
337
|
```
|
330
338
|
|
331
|
-
#### Migrating Existing Files
|
332
|
-
|
333
|
-
**Note:** This feature is experimental. Please try it in a non-production environment and [share](https://github.com/ankane/lockbox/issues/44) how it goes.
|
339
|
+
#### Migrating Existing Files
|
334
340
|
|
335
341
|
Lockbox makes it easy to encrypt existing files without downtime.
|
336
342
|
|
@@ -371,7 +377,7 @@ Encryption is applied to all versions after processing.
|
|
371
377
|
You can mount the uploader [as normal](https://github.com/carrierwaveuploader/carrierwave#activerecord). With Active Record, this involves creating a migration:
|
372
378
|
|
373
379
|
```ruby
|
374
|
-
class AddLicenseToUsers < ActiveRecord::Migration[6.
|
380
|
+
class AddLicenseToUsers < ActiveRecord::Migration[6.1]
|
375
381
|
def change
|
376
382
|
add_column :users, :license, :string
|
377
383
|
end
|
@@ -560,12 +566,10 @@ Update your model:
|
|
560
566
|
|
561
567
|
```ruby
|
562
568
|
class User < ApplicationRecord
|
563
|
-
encrypts :email, previous_versions: [{
|
569
|
+
encrypts :email, previous_versions: [{master_key: previous_key}]
|
564
570
|
end
|
565
571
|
```
|
566
572
|
|
567
|
-
Use `master_key` instead of `key` if passing the master key.
|
568
|
-
|
569
573
|
To rotate existing records, use:
|
570
574
|
|
571
575
|
```ruby
|
@@ -579,11 +583,9 @@ Once all records are rotated, you can remove `previous_versions` from the model.
|
|
579
583
|
Update your initializer:
|
580
584
|
|
581
585
|
```ruby
|
582
|
-
Lockbox.encrypts_action_text_body(previous_versions: [{
|
586
|
+
Lockbox.encrypts_action_text_body(previous_versions: [{master_key: previous_key}])
|
583
587
|
```
|
584
588
|
|
585
|
-
Use `master_key` instead of `key` if passing the master key.
|
586
|
-
|
587
589
|
To rotate existing records, use:
|
588
590
|
|
589
591
|
```ruby
|
@@ -598,12 +600,10 @@ Update your model:
|
|
598
600
|
|
599
601
|
```ruby
|
600
602
|
class User < ApplicationRecord
|
601
|
-
encrypts_attached :license, previous_versions: [{
|
603
|
+
encrypts_attached :license, previous_versions: [{master_key: previous_key}]
|
602
604
|
end
|
603
605
|
```
|
604
606
|
|
605
|
-
Use `master_key` instead of `key` if passing the master key.
|
606
|
-
|
607
607
|
To rotate existing files, use:
|
608
608
|
|
609
609
|
```ruby
|
@@ -620,12 +620,10 @@ Update your model:
|
|
620
620
|
|
621
621
|
```ruby
|
622
622
|
class LicenseUploader < CarrierWave::Uploader::Base
|
623
|
-
encrypt previous_versions: [{
|
623
|
+
encrypt previous_versions: [{master_key: previous_key}]
|
624
624
|
end
|
625
625
|
```
|
626
626
|
|
627
|
-
Use `master_key` instead of `key` if passing the master key.
|
628
|
-
|
629
627
|
To rotate existing files, use:
|
630
628
|
|
631
629
|
```ruby
|
@@ -700,7 +698,7 @@ This is the default algorithm. It’s:
|
|
700
698
|
|
701
699
|
Lockbox uses 256-bit keys.
|
702
700
|
|
703
|
-
**For users who do a lot of encryptions:** You should rotate an individual key after 2 billion encryptions to minimize the chance of a [nonce collision](https://www.cryptologie.net/article/402/is-symmetric-security-solved/), which will expose the key. Each database field and file uploader use a different key (derived from the master key) to extend this window.
|
701
|
+
**For users who do a lot of encryptions:** You should rotate an individual key after 2 billion encryptions to minimize the chance of a [nonce collision](https://www.cryptologie.net/article/402/is-symmetric-security-solved/), which will expose the authentication key. Each database field and file uploader use a different key (derived from the master key) to extend this window.
|
704
702
|
|
705
703
|
### XSalsa20
|
706
704
|
|
@@ -989,7 +987,7 @@ lockbox.decrypt(ciphertext, associated_data: "othercontext") # fails
|
|
989
987
|
You can use `binary` columns for the ciphertext instead of `text` columns.
|
990
988
|
|
991
989
|
```ruby
|
992
|
-
class AddEmailCiphertextToUsers < ActiveRecord::Migration[6.
|
990
|
+
class AddEmailCiphertextToUsers < ActiveRecord::Migration[6.1]
|
993
991
|
def change
|
994
992
|
add_column :users, :email_ciphertext, :binary
|
995
993
|
end
|
@@ -1034,7 +1032,7 @@ end
|
|
1034
1032
|
Create a migration with:
|
1035
1033
|
|
1036
1034
|
```ruby
|
1037
|
-
class MigrateToLockbox < ActiveRecord::Migration[6.
|
1035
|
+
class MigrateToLockbox < ActiveRecord::Migration[6.1]
|
1038
1036
|
def change
|
1039
1037
|
add_column :users, :name_ciphertext, :text
|
1040
1038
|
add_column :users, :email_ciphertext, :text
|
@@ -1067,7 +1065,7 @@ end
|
|
1067
1065
|
Then remove the previous gem from your Gemfile and drop its columns.
|
1068
1066
|
|
1069
1067
|
```ruby
|
1070
|
-
class RemovePreviousEncryptedColumns < ActiveRecord::Migration[6.
|
1068
|
+
class RemovePreviousEncryptedColumns < ActiveRecord::Migration[6.1]
|
1071
1069
|
def change
|
1072
1070
|
remove_column :users, :encrypted_name, :text
|
1073
1071
|
remove_column :users, :encrypted_name_iv, :text
|
@@ -1079,12 +1077,29 @@ end
|
|
1079
1077
|
|
1080
1078
|
## Upgrading
|
1081
1079
|
|
1080
|
+
### 0.6.0
|
1081
|
+
|
1082
|
+
0.6.0 adds `encrypted: true` to Active Storage metadata for new files. This field is informational, but if you prefer to add it to existing files, use:
|
1083
|
+
|
1084
|
+
```ruby
|
1085
|
+
User.with_attached_license.find_each do |user|
|
1086
|
+
next unless user.license.attached?
|
1087
|
+
|
1088
|
+
metadata = user.license.metadata
|
1089
|
+
unless metadata["encrypted"]
|
1090
|
+
user.license.blob.update!(metadata: metadata.merge("encrypted" => true))
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
```
|
1094
|
+
|
1082
1095
|
### 0.3.6
|
1083
1096
|
|
1084
1097
|
0.3.6 makes content type detection more reliable for Active Storage. You can check and update the content type of existing files with:
|
1085
1098
|
|
1086
1099
|
```ruby
|
1087
|
-
User.find_each do |user|
|
1100
|
+
User.with_attached_license.find_each do |user|
|
1101
|
+
next unless user.license.attached?
|
1102
|
+
|
1088
1103
|
license = user.license
|
1089
1104
|
content_type = Marcel::MimeType.for(license.download, name: license.filename.to_s)
|
1090
1105
|
if content_type != license.content_type
|
@@ -16,9 +16,7 @@ module Lockbox
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def data_type
|
19
|
-
|
20
|
-
# so database connection isn't needed
|
21
|
-
case ActiveRecord::Base.connection_config[:adapter].to_s
|
19
|
+
case adapter
|
22
20
|
when /postg/i # postgres, postgis
|
23
21
|
"jsonb"
|
24
22
|
when /mysql/i
|
@@ -27,6 +25,16 @@ module Lockbox
|
|
27
25
|
"text"
|
28
26
|
end
|
29
27
|
end
|
28
|
+
|
29
|
+
# use connection_config instead of connection.adapter
|
30
|
+
# so database connection isn't needed
|
31
|
+
def adapter
|
32
|
+
if ActiveRecord::VERSION::STRING.to_f >= 6.1
|
33
|
+
ActiveRecord::Base.connection_db_config.adapter.to_s
|
34
|
+
else
|
35
|
+
ActiveRecord::Base.connection_config[:adapter].to_s
|
36
|
+
end
|
37
|
+
end
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
data/lib/lockbox.rb
CHANGED
@@ -27,13 +27,22 @@ end
|
|
27
27
|
|
28
28
|
if defined?(ActiveSupport.on_load)
|
29
29
|
ActiveSupport.on_load(:active_record) do
|
30
|
+
# TODO raise error in 0.7.0
|
31
|
+
if ActiveRecord::VERSION::STRING.to_f <= 5.0
|
32
|
+
warn "Active Record version (#{ActiveRecord::VERSION::STRING}) not supported in this version of Lockbox (#{Lockbox::VERSION})"
|
33
|
+
end
|
34
|
+
|
30
35
|
extend Lockbox::Model
|
31
36
|
extend Lockbox::Model::Attached
|
32
|
-
|
37
|
+
# alias_method is private in Ruby < 2.5
|
38
|
+
singleton_class.send(:alias_method, :encrypts, :lockbox_encrypts) if ActiveRecord::VERSION::MAJOR < 7
|
39
|
+
ActiveRecord::Relation.prepend Lockbox::Calculations
|
33
40
|
end
|
34
41
|
|
35
42
|
ActiveSupport.on_load(:mongoid) do
|
36
43
|
Mongoid::Document::ClassMethods.include(Lockbox::Model)
|
44
|
+
# alias_method is private in Ruby < 2.5
|
45
|
+
Mongoid::Document::ClassMethods.send(:alias_method, :encrypts, :lockbox_encrypts)
|
37
46
|
end
|
38
47
|
end
|
39
48
|
|
@@ -101,7 +110,7 @@ module Lockbox
|
|
101
110
|
|
102
111
|
def self.encrypts_action_text_body(**options)
|
103
112
|
ActiveSupport.on_load(:action_text_rich_text) do
|
104
|
-
ActionText::RichText.
|
113
|
+
ActionText::RichText.lockbox_encrypts :body, **options
|
105
114
|
end
|
106
115
|
end
|
107
116
|
end
|
@@ -32,9 +32,17 @@ module Lockbox
|
|
32
32
|
read.bytesize
|
33
33
|
end
|
34
34
|
|
35
|
-
# based on CarrierWave::SanitizedFile#mime_magic_content_type
|
36
35
|
def content_type
|
37
|
-
|
36
|
+
if Gem::Version.new(CarrierWave::VERSION) >= Gem::Version.new("2.2.1")
|
37
|
+
# based on CarrierWave::SanitizedFile#marcel_magic_content_type
|
38
|
+
Marcel::Magic.by_magic(read).try(:type) || "invalid/invalid"
|
39
|
+
elsif CarrierWave::VERSION.to_i >= 2
|
40
|
+
# based on CarrierWave::SanitizedFile#mime_magic_content_type
|
41
|
+
MimeMagic.by_magic(read).try(:type) || "invalid/invalid"
|
42
|
+
else
|
43
|
+
# uses filename
|
44
|
+
super
|
45
|
+
end
|
38
46
|
end
|
39
47
|
|
40
48
|
# disable processing since already processed
|
@@ -98,7 +106,10 @@ module Lockbox
|
|
98
106
|
end
|
99
107
|
|
100
108
|
if CarrierWave::VERSION.to_i > 2
|
101
|
-
raise "CarrierWave version not supported in this version of Lockbox
|
109
|
+
raise "CarrierWave version (#{CarrierWave::VERSION}) not supported in this version of Lockbox (#{Lockbox::VERSION})"
|
110
|
+
elsif CarrierWave::VERSION.to_i < 1
|
111
|
+
# TODO raise error in 0.7.0
|
112
|
+
warn "CarrierWave version (#{CarrierWave::VERSION}) not supported in this version of Lockbox (#{Lockbox::VERSION})"
|
102
113
|
end
|
103
114
|
|
104
115
|
CarrierWave::Uploader::Base.extend(Lockbox::CarrierWaveExtensions)
|
data/lib/lockbox/model.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Lockbox
|
2
2
|
module Model
|
3
|
-
def
|
3
|
+
def lockbox_encrypts(*attributes, **options)
|
4
4
|
# support objects
|
5
5
|
# case options[:type]
|
6
6
|
# when Date
|
@@ -22,7 +22,8 @@ module Lockbox
|
|
22
22
|
# end
|
23
23
|
|
24
24
|
custom_type = options[:type].respond_to?(:serialize) && options[:type].respond_to?(:deserialize)
|
25
|
-
|
25
|
+
valid_types = [nil, :string, :boolean, :date, :datetime, :time, :integer, :float, :binary, :json, :hash, :array, :inet]
|
26
|
+
raise ArgumentError, "Unknown type: #{options[:type]}" unless custom_type || valid_types.include?(options[:type])
|
26
27
|
|
27
28
|
activerecord = defined?(ActiveRecord::Base) && self < ActiveRecord::Base
|
28
29
|
raise ArgumentError, "Type not supported yet with Mongoid" if options[:type] && !activerecord
|
@@ -148,16 +149,38 @@ module Lockbox
|
|
148
149
|
# needed for in-place modifications
|
149
150
|
# assigned attributes are encrypted on assignment
|
150
151
|
# and then again here
|
151
|
-
|
152
|
+
def lockbox_sync_attributes
|
152
153
|
self.class.lockbox_attributes.each do |_, lockbox_attribute|
|
153
154
|
attribute = lockbox_attribute[:attribute]
|
154
155
|
|
155
|
-
if attribute_changed_in_place?(attribute)
|
156
|
+
if attribute_changed_in_place?(attribute) || (send("#{attribute}_changed?") && !send("#{lockbox_attribute[:encrypted_attribute]}_changed?"))
|
156
157
|
send("#{attribute}=", send(attribute))
|
157
158
|
end
|
158
159
|
end
|
159
160
|
end
|
160
161
|
|
162
|
+
# safety check
|
163
|
+
[:_create_record, :_update_record].each do |method_name|
|
164
|
+
unless private_method_defined?(method_name) || method_defined?(method_name)
|
165
|
+
raise Lockbox::Error, "Expected #{method_name} to be defined. Please report an issue."
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def _create_record(*)
|
170
|
+
lockbox_sync_attributes
|
171
|
+
super
|
172
|
+
end
|
173
|
+
|
174
|
+
def _update_record(*)
|
175
|
+
lockbox_sync_attributes
|
176
|
+
super
|
177
|
+
end
|
178
|
+
|
179
|
+
def [](attr_name)
|
180
|
+
send(attr_name) if self.class.lockbox_attributes.any? { |_, la| la[:attribute] == attr_name.to_s }
|
181
|
+
super
|
182
|
+
end
|
183
|
+
|
161
184
|
def update_columns(attributes)
|
162
185
|
return super unless attributes.is_a?(Hash)
|
163
186
|
|
@@ -193,8 +216,11 @@ module Lockbox
|
|
193
216
|
attributes_to_set.each do |k, v|
|
194
217
|
if respond_to?(:write_attribute_without_type_cast, true)
|
195
218
|
write_attribute_without_type_cast(k, v)
|
196
|
-
|
219
|
+
elsif respond_to?(:raw_write_attribute, true)
|
197
220
|
raw_write_attribute(k, v)
|
221
|
+
else
|
222
|
+
@attributes.write_cast_value(k, v)
|
223
|
+
clear_attribute_change(k)
|
198
224
|
end
|
199
225
|
end
|
200
226
|
|
@@ -247,6 +273,23 @@ module Lockbox
|
|
247
273
|
else
|
248
274
|
attribute name, :string
|
249
275
|
end
|
276
|
+
else
|
277
|
+
# hack for Active Record 6.1
|
278
|
+
# to set string type after serialize
|
279
|
+
# otherwise, type gets set to ActiveModel::Type::Value
|
280
|
+
# which always returns false for changed_in_place?
|
281
|
+
# earlier versions of Active Record take the previous code path
|
282
|
+
if ActiveRecord::VERSION::STRING.to_f >= 7.0 && attributes_to_define_after_schema_loads[name.to_s].first.is_a?(Proc)
|
283
|
+
attribute_type = attributes_to_define_after_schema_loads[name.to_s].first.call(nil)
|
284
|
+
if attribute_type.is_a?(ActiveRecord::Type::Serialized) && attribute_type.subtype.nil?
|
285
|
+
attribute name, ActiveRecord::Type::Serialized.new(ActiveRecord::Type::String.new, attribute_type.coder)
|
286
|
+
end
|
287
|
+
elsif ActiveRecord::VERSION::STRING.to_f >= 6.1 && attributes_to_define_after_schema_loads[name.to_s].first.is_a?(Proc)
|
288
|
+
attribute_type = attributes_to_define_after_schema_loads[name.to_s].first.call
|
289
|
+
if attribute_type.is_a?(ActiveRecord::Type::Serialized) && attribute_type.subtype.nil?
|
290
|
+
attribute name, ActiveRecord::Type::Serialized.new(ActiveRecord::Type::String.new, attribute_type.coder)
|
291
|
+
end
|
292
|
+
end
|
250
293
|
end
|
251
294
|
|
252
295
|
define_method("#{name}_was") do
|
@@ -358,7 +401,11 @@ module Lockbox
|
|
358
401
|
# check for this explicitly as a layer of safety
|
359
402
|
if message.nil? || ((message == {} || message == []) && activerecord && @attributes[name.to_s].value_before_type_cast.nil?)
|
360
403
|
ciphertext = send(encrypted_attribute)
|
361
|
-
|
404
|
+
|
405
|
+
# keep original message for empty hashes and arrays
|
406
|
+
unless ciphertext.nil?
|
407
|
+
message = self.class.send(decrypt_method_name, ciphertext, context: self)
|
408
|
+
end
|
362
409
|
|
363
410
|
if activerecord
|
364
411
|
# set previous attribute so changes populate correctly
|
@@ -370,8 +417,13 @@ module Lockbox
|
|
370
417
|
# decrypt method does type casting
|
371
418
|
if respond_to?(:write_attribute_without_type_cast, true)
|
372
419
|
write_attribute_without_type_cast(name.to_s, message) if !@attributes.frozen?
|
373
|
-
|
420
|
+
elsif respond_to?(:raw_write_attribute, true)
|
374
421
|
raw_write_attribute(name, message) if !@attributes.frozen?
|
422
|
+
else
|
423
|
+
if !@attributes.frozen?
|
424
|
+
@attributes.write_cast_value(name.to_s, message)
|
425
|
+
clear_attribute_change(name)
|
426
|
+
end
|
375
427
|
end
|
376
428
|
else
|
377
429
|
instance_variable_set("@#{name}", message)
|
@@ -414,6 +466,14 @@ module Lockbox
|
|
414
466
|
message = ActiveRecord::Type::Float.new.serialize(message)
|
415
467
|
# double precision, big endian
|
416
468
|
message = [message].pack("G") unless message.nil?
|
469
|
+
when :inet
|
470
|
+
unless message.nil?
|
471
|
+
ip = message.is_a?(IPAddr) ? message : (IPAddr.new(message) rescue nil)
|
472
|
+
# same format as Postgres, with ipv4 padded to 16 bytes
|
473
|
+
# family, netmask, ip
|
474
|
+
# return nil for invalid IP like Active Record
|
475
|
+
message = ip ? [ip.ipv4? ? 0 : 1, ip.prefix, ip.hton].pack("CCa16") : nil
|
476
|
+
end
|
417
477
|
when :string, :binary
|
418
478
|
# do nothing
|
419
479
|
# encrypt will convert to binary
|
@@ -460,6 +520,11 @@ module Lockbox
|
|
460
520
|
when :binary
|
461
521
|
# do nothing
|
462
522
|
# decrypt returns binary string
|
523
|
+
when :inet
|
524
|
+
family, prefix, addr = message.unpack("CCa16")
|
525
|
+
len = family == 0 ? 4 : 16
|
526
|
+
message = IPAddr.new_ntoh(addr.first(len))
|
527
|
+
message.prefix = prefix
|
463
528
|
else
|
464
529
|
# use original name for serialized attributes
|
465
530
|
type = (try(:attribute_types) || {})[original_name.to_s]
|
data/lib/lockbox/railtie.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
module Lockbox
|
2
2
|
class Railtie < Rails::Railtie
|
3
3
|
initializer "lockbox" do |app|
|
4
|
+
if defined?(Rails.application.credentials)
|
5
|
+
# needs to work when lockbox key has a string value
|
6
|
+
Lockbox.master_key ||= Rails.application.credentials.try(:lockbox).try(:fetch, :master_key, nil)
|
7
|
+
end
|
8
|
+
|
4
9
|
require "lockbox/carrier_wave_extensions" if defined?(CarrierWave)
|
5
10
|
|
6
11
|
if defined?(ActiveStorage)
|
@@ -14,7 +19,14 @@ module Lockbox
|
|
14
19
|
ActiveStorage::Attached::Many.prepend(Lockbox::ActiveStorageExtensions::AttachedMany)
|
15
20
|
|
16
21
|
# use load hooks when possible
|
17
|
-
if ActiveStorage::VERSION::MAJOR >=
|
22
|
+
if ActiveStorage::VERSION::MAJOR >= 7
|
23
|
+
ActiveSupport.on_load(:active_storage_attachment) do
|
24
|
+
prepend Lockbox::ActiveStorageExtensions::Attachment
|
25
|
+
end
|
26
|
+
ActiveSupport.on_load(:active_storage_blob) do
|
27
|
+
prepend Lockbox::ActiveStorageExtensions::Blob
|
28
|
+
end
|
29
|
+
elsif ActiveStorage::VERSION::MAJOR >= 6
|
18
30
|
ActiveSupport.on_load(:active_storage_attachment) do
|
19
31
|
include Lockbox::ActiveStorageExtensions::Attachment
|
20
32
|
end
|
data/lib/lockbox/version.rb
CHANGED
metadata
CHANGED
@@ -1,199 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lockbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: carrierwave
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: combustion
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.3'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.3'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rails
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: minitest
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '5'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '5'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rake
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rbnacl
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '6'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '6'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: sqlite3
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: pg
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: mysql2
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - ">="
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: shrine
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - ">="
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - ">="
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: shrine-mongoid
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - ">="
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - ">="
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: benchmark-ips
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - ">="
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '0'
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - ">="
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '0'
|
11
|
+
date: 2021-07-07 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
195
13
|
description:
|
196
|
-
email: andrew@
|
14
|
+
email: andrew@ankane.org
|
197
15
|
executables: []
|
198
16
|
extensions: []
|
199
17
|
extra_rdoc_files: []
|
@@ -240,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
240
58
|
- !ruby/object:Gem::Version
|
241
59
|
version: '0'
|
242
60
|
requirements: []
|
243
|
-
rubygems_version: 3.
|
61
|
+
rubygems_version: 3.2.3
|
244
62
|
signing_key:
|
245
63
|
specification_version: 4
|
246
64
|
summary: Modern encryption for Ruby and Rails
|