lockbox 1.3.3 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -16
- data/lib/lockbox/carrier_wave_extensions.rb +1 -1
- data/lib/lockbox/migrator.rb +1 -1
- data/lib/lockbox/model.rb +83 -34
- data/lib/lockbox/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c227a11280d70eaaa03e7c81649bee696c2c88ab9a1825503f7db4e9af5d2d12
|
4
|
+
data.tar.gz: 52a2969568229aefa391a093c93ae1771d021ddc2396d3e4f65ec2f509a82c41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1734e1db6d559ed4221e81b30ca6a13db348a6089f58581376ce4cf16019a5787f8dd1b80abd1534ef2c82e294db4db1d8cb30089413d4e2e009544d3185d350
|
7
|
+
data.tar.gz: d5bdb1947c5fac19038fe21651bf35d32d675eba024569ec085b015ad991a9c1ea5e65437df908f78e0083486726032571c6dee364fe92a95a7447e33495cf83
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -194,7 +194,7 @@ class User < ApplicationRecord
|
|
194
194
|
has_encrypted :email
|
195
195
|
|
196
196
|
# remove this line after dropping email column
|
197
|
-
self.ignored_columns
|
197
|
+
self.ignored_columns += ["email"]
|
198
198
|
end
|
199
199
|
```
|
200
200
|
|
@@ -1016,21 +1016,6 @@ class User < ApplicationRecord
|
|
1016
1016
|
end
|
1017
1017
|
```
|
1018
1018
|
|
1019
|
-
### 0.6.0
|
1020
|
-
|
1021
|
-
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:
|
1022
|
-
|
1023
|
-
```ruby
|
1024
|
-
User.with_attached_license.find_each do |user|
|
1025
|
-
next unless user.license.attached?
|
1026
|
-
|
1027
|
-
metadata = user.license.metadata
|
1028
|
-
unless metadata["encrypted"]
|
1029
|
-
user.license.blob.update!(metadata: metadata.merge("encrypted" => true))
|
1030
|
-
end
|
1031
|
-
end
|
1032
|
-
```
|
1033
|
-
|
1034
1019
|
## History
|
1035
1020
|
|
1036
1021
|
View the [changelog](https://github.com/ankane/lockbox/blob/master/CHANGELOG.md)
|
data/lib/lockbox/migrator.rb
CHANGED
@@ -2,7 +2,7 @@ module Lockbox
|
|
2
2
|
class Migrator
|
3
3
|
def initialize(relation, batch_size:)
|
4
4
|
@relation = relation
|
5
|
-
@transaction = @relation.respond_to?(:transaction)
|
5
|
+
@transaction = @relation.respond_to?(:transaction) && !mongoid_relation?(base_relation)
|
6
6
|
@batch_size = batch_size
|
7
7
|
end
|
8
8
|
|
data/lib/lockbox/model.rb
CHANGED
@@ -137,13 +137,16 @@ module Lockbox
|
|
137
137
|
# essentially a no-op if already loaded
|
138
138
|
# an exception is thrown if decryption fails
|
139
139
|
self.class.lockbox_attributes.each do |_, lockbox_attribute|
|
140
|
-
# don't try to decrypt if no decryption key given
|
141
|
-
next if lockbox_attribute[:algorithm] == "hybrid" && lockbox_attribute[:decryption_key].nil?
|
142
|
-
|
143
140
|
# it is possible that the encrypted attribute is not loaded, eg.
|
144
141
|
# if the record was fetched partially (`User.select(:id).first`).
|
145
142
|
# accessing a not loaded attribute raises an `ActiveModel::MissingAttributeError`.
|
146
|
-
|
143
|
+
if has_attribute?(lockbox_attribute[:encrypted_attribute])
|
144
|
+
begin
|
145
|
+
send(lockbox_attribute[:attribute])
|
146
|
+
rescue ArgumentError => e
|
147
|
+
raise e if e.message != "No decryption key set"
|
148
|
+
end
|
149
|
+
end
|
147
150
|
end
|
148
151
|
super
|
149
152
|
end
|
@@ -230,6 +233,20 @@ module Lockbox
|
|
230
233
|
end
|
231
234
|
|
232
235
|
if ActiveRecord::VERSION::MAJOR >= 6
|
236
|
+
if ActiveRecord::VERSION::STRING.to_f >= 7.2
|
237
|
+
def self.insert(attributes, **options)
|
238
|
+
super(lockbox_map_record_attributes(attributes), **options)
|
239
|
+
end
|
240
|
+
|
241
|
+
def self.insert!(attributes, **options)
|
242
|
+
super(lockbox_map_record_attributes(attributes), **options)
|
243
|
+
end
|
244
|
+
|
245
|
+
def self.upsert(attributes, **options)
|
246
|
+
super(lockbox_map_record_attributes(attributes, check_readonly: true), **options)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
233
250
|
def self.insert_all(attributes, **options)
|
234
251
|
super(lockbox_map_attributes(attributes), **options)
|
235
252
|
end
|
@@ -248,30 +265,37 @@ module Lockbox
|
|
248
265
|
return records unless records.is_a?(Array)
|
249
266
|
|
250
267
|
records.map do |attributes|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
attribute_aliases[n] || n
|
255
|
-
end
|
268
|
+
lockbox_map_record_attributes(attributes, check_readonly: false)
|
269
|
+
end
|
270
|
+
end
|
256
271
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
272
|
+
# private
|
273
|
+
def self.lockbox_map_record_attributes(attributes, check_readonly: false)
|
274
|
+
return attributes unless attributes.is_a?(Hash)
|
275
|
+
|
276
|
+
# transform keys like Active Record
|
277
|
+
attributes = attributes.transform_keys do |key|
|
278
|
+
n = key.to_s
|
279
|
+
attribute_aliases[n] || n
|
280
|
+
end
|
281
|
+
|
282
|
+
lockbox_attributes = self.lockbox_attributes.slice(*attributes.keys.map(&:to_sym))
|
283
|
+
lockbox_attributes.each do |key, lockbox_attribute|
|
284
|
+
attribute = key.to_s
|
285
|
+
# check read only
|
286
|
+
# users should mark both plaintext and ciphertext columns
|
287
|
+
if check_readonly && readonly_attributes.include?(attribute) && !readonly_attributes.include?(lockbox_attribute[:encrypted_attribute].to_s)
|
288
|
+
warn "[lockbox] WARNING: Mark attribute as readonly: #{lockbox_attribute[:encrypted_attribute]}"
|
271
289
|
end
|
272
290
|
|
273
|
-
attributes
|
291
|
+
message = attributes[attribute]
|
292
|
+
attributes.delete(attribute) unless lockbox_attribute[:migrating]
|
293
|
+
encrypted_attribute = lockbox_attribute[:encrypted_attribute]
|
294
|
+
ciphertext = send("generate_#{encrypted_attribute}", message)
|
295
|
+
attributes[encrypted_attribute] = ciphertext
|
274
296
|
end
|
297
|
+
|
298
|
+
attributes
|
275
299
|
end
|
276
300
|
end
|
277
301
|
else
|
@@ -295,7 +319,12 @@ module Lockbox
|
|
295
319
|
end
|
296
320
|
|
297
321
|
# warn on default attributes
|
298
|
-
if
|
322
|
+
if ActiveRecord::VERSION::STRING.to_f >= 7.2
|
323
|
+
# TODO improve
|
324
|
+
if pending_attribute_modifications.any? { |v| v.is_a?(ActiveModel::AttributeRegistration::ClassMethods::PendingDefault) && v.name == name.to_s }
|
325
|
+
warn "[lockbox] WARNING: attributes with `:default` option are not supported. Use `after_initialize` instead."
|
326
|
+
end
|
327
|
+
elsif attributes_to_define_after_schema_loads.key?(name.to_s)
|
299
328
|
opt = attributes_to_define_after_schema_loads[name.to_s][1]
|
300
329
|
|
301
330
|
has_default =
|
@@ -347,6 +376,26 @@ module Lockbox
|
|
347
376
|
serialize name, Array
|
348
377
|
end
|
349
378
|
end
|
379
|
+
elsif ActiveRecord::VERSION::STRING.to_f >= 7.2
|
380
|
+
decorate_attributes([name]) do |attr_name, cast_type|
|
381
|
+
if cast_type.instance_of?(ActiveRecord::Type::Value)
|
382
|
+
original_type = pending_attribute_modifications.find { |v| v.is_a?(ActiveModel::AttributeRegistration::ClassMethods::PendingType) && v.name == original_name.to_s && !v.type.nil? }&.type
|
383
|
+
if original_type
|
384
|
+
original_type
|
385
|
+
elsif options[:migrating]
|
386
|
+
cast_type
|
387
|
+
else
|
388
|
+
ActiveRecord::Type::String.new
|
389
|
+
end
|
390
|
+
elsif cast_type.is_a?(ActiveRecord::Type::Serialized) && cast_type.subtype.instance_of?(ActiveModel::Type::Value)
|
391
|
+
# hack to set string type after serialize
|
392
|
+
# otherwise, type gets set to ActiveModel::Type::Value
|
393
|
+
# which always returns false for changed_in_place?
|
394
|
+
ActiveRecord::Type::Serialized.new(ActiveRecord::Type::String.new, cast_type.coder)
|
395
|
+
else
|
396
|
+
cast_type
|
397
|
+
end
|
398
|
+
end
|
350
399
|
elsif !attributes_to_define_after_schema_loads.key?(name.to_s)
|
351
400
|
# when migrating it's best to specify the type directly
|
352
401
|
# however, we can try to use the original type if its already defined
|
@@ -360,8 +409,7 @@ module Lockbox
|
|
360
409
|
attribute name, :string
|
361
410
|
end
|
362
411
|
else
|
363
|
-
# hack for Active Record 6.1
|
364
|
-
# to set string type after serialize
|
412
|
+
# hack for Active Record 6.1+ to set string type after serialize
|
365
413
|
# otherwise, type gets set to ActiveModel::Type::Value
|
366
414
|
# which always returns false for changed_in_place?
|
367
415
|
# earlier versions of Active Record take the previous code path
|
@@ -447,12 +495,12 @@ module Lockbox
|
|
447
495
|
# decrypt first for dirty tracking
|
448
496
|
# don't raise error if can't decrypt previous
|
449
497
|
# don't try to decrypt if no decryption key given
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
498
|
+
begin
|
499
|
+
send(name)
|
500
|
+
rescue Lockbox::DecryptionError
|
501
|
+
warn "[lockbox] Decrypting previous value failed"
|
502
|
+
rescue ArgumentError => e
|
503
|
+
raise e if e.message != "No decryption key set"
|
456
504
|
end
|
457
505
|
|
458
506
|
send("lockbox_direct_#{name}=", message)
|
@@ -669,7 +717,8 @@ module Lockbox
|
|
669
717
|
end
|
670
718
|
|
671
719
|
def lockbox_encrypts(*attributes, **options)
|
672
|
-
ActiveSupport::
|
720
|
+
deprecator = ActiveSupport::VERSION::STRING.to_f >= 7.2 ? ActiveSupport.deprecator : ActiveSupport::Deprecation
|
721
|
+
deprecator.warn("`#{__callee__}` is deprecated in favor of `has_encrypted`")
|
673
722
|
has_encrypted(*attributes, **options)
|
674
723
|
end
|
675
724
|
|
data/lib/lockbox/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lockbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: andrew@ankane.org
|
@@ -58,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
58
|
- !ruby/object:Gem::Version
|
59
59
|
version: '0'
|
60
60
|
requirements: []
|
61
|
-
rubygems_version: 3.5.
|
61
|
+
rubygems_version: 3.5.11
|
62
62
|
signing_key:
|
63
63
|
specification_version: 4
|
64
64
|
summary: Modern encryption for Ruby and Rails
|