lockbox 0.3.2 → 0.3.3
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 +5 -0
- data/README.md +1 -1
- data/lib/lockbox/migrator.rb +52 -16
- data/lib/lockbox/model.rb +11 -5
- data/lib/lockbox/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8198d9c7bf3be294c7efc7c7d03abbe64ccf8d487a0a81ad01151b225dbfde92
|
4
|
+
data.tar.gz: dd51f9c1dc06a4cc657fb8b25a05f4a2960a2bce6883fd97dd41d1ac7e426e91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe9c1274693558f3e184b7881f027c0e1ce895aeacd2c222451ea87a61ed7ff1064ed324a2e11a3bf35f60fa3647698ded89574a8c378ef42c0b538fe6606e1c
|
7
|
+
data.tar.gz: 65ea6fb170250edf535692e085700430e4fe25ebca07e63d17de7e2f99afcb0d3089787a4b90c193b3314ae9bcde9540454eae3685a242da1e166c36d2982b19
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -176,7 +176,7 @@ end
|
|
176
176
|
|
177
177
|
Finally, drop the unencrypted column.
|
178
178
|
|
179
|
-
If adding blind indexes,
|
179
|
+
If adding blind indexes, mark them as `migrating` during this process as well.
|
180
180
|
|
181
181
|
```ruby
|
182
182
|
class User < ApplicationRecord
|
data/lib/lockbox/migrator.rb
CHANGED
@@ -13,19 +13,20 @@ module Lockbox
|
|
13
13
|
def rotate(attributes:)
|
14
14
|
fields = {}
|
15
15
|
attributes.each do |a|
|
16
|
-
# use key
|
16
|
+
# use key instead of v[:attribute] to make it more intuitive when migrating: true
|
17
17
|
field = model.lockbox_attributes[a]
|
18
18
|
raise ArgumentError, "Bad attribute: #{a}" unless field
|
19
19
|
fields[a] = field
|
20
20
|
end
|
21
21
|
|
22
|
-
perform(fields: fields)
|
22
|
+
perform(fields: fields, rotate: true)
|
23
23
|
end
|
24
24
|
|
25
25
|
# TODO add attributes option
|
26
26
|
def migrate(restart:)
|
27
27
|
fields = model.lockbox_attributes.select { |k, v| v[:migrating] }
|
28
28
|
|
29
|
+
# need blind indexes for building relation
|
29
30
|
blind_indexes = model.respond_to?(:blind_indexes) ? model.blind_indexes.select { |k, v| v[:migrating] } : {}
|
30
31
|
|
31
32
|
perform(fields: fields, blind_indexes: blind_indexes, restart: restart)
|
@@ -33,11 +34,14 @@ module Lockbox
|
|
33
34
|
|
34
35
|
private
|
35
36
|
|
36
|
-
def perform(fields:, blind_indexes: [], restart: true)
|
37
|
+
def perform(fields:, blind_indexes: [], restart: true, rotate: false)
|
37
38
|
relation = @relation
|
38
39
|
|
39
|
-
#
|
40
|
-
|
40
|
+
# unscope if passed a model
|
41
|
+
unless ar_relation?(relation) || mongoid_relation?(relation)
|
42
|
+
relation = relation.unscoped
|
43
|
+
else
|
44
|
+
# TODO remove in 0.4.0
|
41
45
|
relation = relation.unscoped
|
42
46
|
end
|
43
47
|
|
@@ -48,7 +52,7 @@ module Lockbox
|
|
48
52
|
attributes = fields.map { |_, v| v[:encrypted_attribute] }
|
49
53
|
attributes += blind_indexes.map { |_, v| v[:bidx_attribute] }
|
50
54
|
|
51
|
-
if
|
55
|
+
if ar_relation?(relation)
|
52
56
|
base_relation = relation.unscoped
|
53
57
|
or_relation = relation.unscoped
|
54
58
|
|
@@ -68,7 +72,7 @@ module Lockbox
|
|
68
72
|
end
|
69
73
|
|
70
74
|
each_batch(relation) do |records|
|
71
|
-
migrate_records(records, fields: fields, blind_indexes: blind_indexes, restart: restart)
|
75
|
+
migrate_records(records, fields: fields, blind_indexes: blind_indexes, restart: restart, rotate: rotate)
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
@@ -92,27 +96,59 @@ module Lockbox
|
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
95
|
-
def migrate_records(records, fields:, blind_indexes:, restart:)
|
99
|
+
def migrate_records(records, fields:, blind_indexes:, restart:, rotate:)
|
96
100
|
# do computation outside of transaction
|
97
101
|
# especially expensive blind index computation
|
98
|
-
|
99
|
-
|
100
|
-
|
102
|
+
if rotate
|
103
|
+
records.each do |record|
|
104
|
+
fields.each do |k, v|
|
105
|
+
# update encrypted attribute directly to skip blind index computation
|
106
|
+
record.send("lockbox_direct_#{k}=", record.send(k))
|
107
|
+
end
|
101
108
|
end
|
102
|
-
|
103
|
-
|
109
|
+
else
|
110
|
+
records.each do |record|
|
111
|
+
if restart
|
112
|
+
fields.each do |k, v|
|
113
|
+
record.send("#{v[:encrypted_attribute]}=", nil)
|
114
|
+
end
|
115
|
+
|
116
|
+
blind_indexes.each do |k, v|
|
117
|
+
record.send("#{v[:bidx_attribute]}=", nil)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
fields.each do |k, v|
|
122
|
+
record.send("#{v[:attribute]}=", record.send(k)) unless record.send(v[:encrypted_attribute])
|
123
|
+
end
|
124
|
+
|
125
|
+
# with Blind Index 2.0, bidx_attribute should be already set for each record
|
126
|
+
blind_indexes.each do |k, v|
|
127
|
+
record.send("compute_#{k}_bidx") unless record.send(v[:bidx_attribute])
|
128
|
+
end
|
104
129
|
end
|
105
130
|
end
|
106
131
|
|
132
|
+
# don't need to save records that went from nil => nil
|
107
133
|
records.select! { |r| r.changed? }
|
108
134
|
|
109
|
-
|
110
|
-
|
111
|
-
|
135
|
+
if records.any?
|
136
|
+
with_transaction do
|
137
|
+
records.each do |record|
|
138
|
+
record.save!(validate: false)
|
139
|
+
end
|
112
140
|
end
|
113
141
|
end
|
114
142
|
end
|
115
143
|
|
144
|
+
def ar_relation?(relation)
|
145
|
+
defined?(ActiveRecord::Relation) && relation.is_a?(ActiveRecord::Relation)
|
146
|
+
end
|
147
|
+
|
148
|
+
def mongoid_relation?(relation)
|
149
|
+
defined?(Mongoid::Criteria) && relation.is_a?(Mongoid::Criteria)
|
150
|
+
end
|
151
|
+
|
116
152
|
def with_transaction
|
117
153
|
if @transaction
|
118
154
|
@relation.transaction do
|
data/lib/lockbox/model.rb
CHANGED
@@ -191,22 +191,28 @@ module Lockbox
|
|
191
191
|
end
|
192
192
|
|
193
193
|
define_method("#{name}=") do |message|
|
194
|
-
original_message = message
|
195
|
-
|
196
194
|
# decrypt first for dirty tracking
|
197
195
|
# don't raise error if can't decrypt previous
|
198
196
|
begin
|
199
197
|
send(name)
|
200
198
|
rescue Lockbox::DecryptionError
|
199
|
+
# this is expected for hybrid cryptography
|
200
|
+
warn "[lockbox] Decrypting previous value failed" unless options[:algorithm] == "hybrid"
|
201
201
|
nil
|
202
202
|
end
|
203
203
|
|
204
|
-
#
|
204
|
+
send("lockbox_direct_#{name}=", message)
|
205
|
+
|
206
|
+
super(message)
|
207
|
+
end
|
208
|
+
|
209
|
+
# separate method for setting directly
|
210
|
+
# used to skip blind indexes for key rotation
|
211
|
+
define_method("lockbox_direct_#{name}=") do |message|
|
205
212
|
ciphertext = self.class.send(encrypt_method_name, message, context: self)
|
206
213
|
send("#{encrypted_attribute}=", ciphertext)
|
207
|
-
|
208
|
-
super(original_message)
|
209
214
|
end
|
215
|
+
private :"lockbox_direct_#{name}="
|
210
216
|
|
211
217
|
define_method(name) do
|
212
218
|
message = super()
|
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: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|