lockbox 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -7
- data/README.md +54 -9
- data/lib/lockbox.rb +5 -0
- data/lib/lockbox/model.rb +57 -50
- 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: 33199b663aaa289ff221bd83278063e366501185112f9aea61ea52997c6646fb
|
4
|
+
data.tar.gz: 3d8556b252b574c69cd50244cc752302825cae423daf6bcbac5a0f07b6a83d9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9246245fe128a27292ee9a365ab04fcb0acfd3336b838aeef5756353d35add2248911916e6dec4ed46cb0adf01576ac8fb98066cb6a35aec7827144d5d208d40
|
7
|
+
data.tar.gz: 98273c362d05eca1b66cc578264c18db1a66007fd461ae0d3d8919305f9c34b9af70450a5fe3b318357fe296fc0455b52f52d7b2313a04269101fdf50b408df4
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
## 0.2.
|
1
|
+
## 0.2.5 (2019-12-14)
|
2
|
+
|
3
|
+
- Made `model.attribute?` consistent with unencrypted columns
|
4
|
+
- Added `decrypt_str` method
|
5
|
+
- Improved fixtures for attributes with `type` option
|
6
|
+
|
7
|
+
## 0.2.4 (2019-08-16)
|
2
8
|
|
3
9
|
- Added support for Mongoid
|
4
10
|
- Added `encrypt_io` and `decrypt_io` methods
|
@@ -6,36 +12,36 @@
|
|
6
12
|
- Fixed error with migrate and default scope
|
7
13
|
- Fixed encryption with Active Storage 6 and `record.create!`
|
8
14
|
|
9
|
-
## 0.2.3
|
15
|
+
## 0.2.3 (2019-07-31)
|
10
16
|
|
11
17
|
- Added time type
|
12
18
|
- Added support for rotating padding with same key
|
13
19
|
- Fixed `OpenSSL::KDF` error on some platforms
|
14
20
|
- Fixed UTF-8 error
|
15
21
|
|
16
|
-
## 0.2.2
|
22
|
+
## 0.2.2 (2019-07-24)
|
17
23
|
|
18
24
|
- Fixed error with models that have attachments but no encrypted attachments
|
19
25
|
|
20
|
-
## 0.2.1
|
26
|
+
## 0.2.1 (2019-07-22)
|
21
27
|
|
22
28
|
- Added support for types
|
23
29
|
- Added support for serialized attributes
|
24
30
|
- Added support for padding
|
25
31
|
- Added `encode` option for binary columns
|
26
32
|
|
27
|
-
## 0.2.0
|
33
|
+
## 0.2.0 (2019-07-08)
|
28
34
|
|
29
35
|
- Added `encrypts` method for database fields
|
30
36
|
- Added `encrypts_attached` method
|
31
37
|
- Added `generate_key` method
|
32
38
|
- Added support for XSalsa20
|
33
39
|
|
34
|
-
## 0.1.1
|
40
|
+
## 0.1.1 (2019-02-28)
|
35
41
|
|
36
42
|
- Added support for hybrid cryptography
|
37
43
|
- Added support for database fields
|
38
44
|
|
39
|
-
## 0.1.0
|
45
|
+
## 0.1.0 (2019-01-02)
|
40
46
|
|
41
47
|
- First release
|
data/README.md
CHANGED
@@ -44,6 +44,24 @@ Lockbox.master_key = Rails.application.credentials.lockbox_master_key
|
|
44
44
|
|
45
45
|
Alternatively, you can use a [key management service](#key-management) to manage your keys.
|
46
46
|
|
47
|
+
## Instructions
|
48
|
+
|
49
|
+
Database fields
|
50
|
+
|
51
|
+
- [Active Record](#active-record)
|
52
|
+
- [Mongoid](#mongoid)
|
53
|
+
|
54
|
+
Files
|
55
|
+
|
56
|
+
- [Active Storage](#active-storage)
|
57
|
+
- [CarrierWave](#carrierwave)
|
58
|
+
- [Shrine](#shrine)
|
59
|
+
- [Local Files](#local-files)
|
60
|
+
|
61
|
+
Other
|
62
|
+
|
63
|
+
- [Strings](#strings)
|
64
|
+
|
47
65
|
## Database Fields
|
48
66
|
|
49
67
|
### Active Record
|
@@ -51,7 +69,7 @@ Alternatively, you can use a [key management service](#key-management) to manage
|
|
51
69
|
Create a migration with:
|
52
70
|
|
53
71
|
```ruby
|
54
|
-
class AddEmailCiphertextToUsers < ActiveRecord::Migration[
|
72
|
+
class AddEmailCiphertextToUsers < ActiveRecord::Migration[6.0]
|
55
73
|
def change
|
56
74
|
add_column :users, :email_ciphertext, :text
|
57
75
|
end
|
@@ -92,7 +110,7 @@ class User < ApplicationRecord
|
|
92
110
|
end
|
93
111
|
```
|
94
112
|
|
95
|
-
**Note:** Always use a `text` or `binary` column in migrations, regardless of the type
|
113
|
+
**Note:** Always use a `text` or `binary` column for the ciphertext in migrations, regardless of the type
|
96
114
|
|
97
115
|
Lockbox automatically works with serialized fields for maximum compatibility with existing code and libraries.
|
98
116
|
|
@@ -100,6 +118,9 @@ Lockbox automatically works with serialized fields for maximum compatibility wit
|
|
100
118
|
class User < ApplicationRecord
|
101
119
|
serialize :properties, JSON
|
102
120
|
encrypts :properties
|
121
|
+
|
122
|
+
store :settings, accessors: [:color, :homepage]
|
123
|
+
encrypts :settings
|
103
124
|
end
|
104
125
|
```
|
105
126
|
|
@@ -247,6 +268,12 @@ Decrypt
|
|
247
268
|
box.decrypt(ciphertext)
|
248
269
|
```
|
249
270
|
|
271
|
+
Decrypt and return UTF-8 instead of binary
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
box.decrypt_str(ciphertext)
|
275
|
+
```
|
276
|
+
|
250
277
|
## Migrating Existing Data
|
251
278
|
|
252
279
|
Lockbox makes it easy to encrypt an existing column. Add a new column for the ciphertext, then add to your model:
|
@@ -384,20 +411,29 @@ Heroku [comes with libsodium](https://devcenter.heroku.com/articles/stack-packag
|
|
384
411
|
|
385
412
|
##### Ubuntu
|
386
413
|
|
387
|
-
For Ubuntu
|
414
|
+
For Ubuntu 18.04, use:
|
388
415
|
|
389
416
|
```sh
|
390
|
-
sudo apt-get install
|
417
|
+
sudo apt-get install libsodium23
|
391
418
|
```
|
392
419
|
|
393
|
-
For Ubuntu
|
420
|
+
For Ubuntu 16.04, use:
|
394
421
|
|
395
422
|
```sh
|
396
|
-
sudo apt-get install
|
423
|
+
sudo apt-get install libsodium18
|
397
424
|
```
|
398
425
|
|
399
426
|
##### Travis CI
|
400
427
|
|
428
|
+
On Bionic, add to `.travis.yml`:
|
429
|
+
|
430
|
+
```yml
|
431
|
+
addons:
|
432
|
+
apt:
|
433
|
+
packages:
|
434
|
+
- libsodium23
|
435
|
+
```
|
436
|
+
|
401
437
|
On Xenial, add to `.travis.yml`:
|
402
438
|
|
403
439
|
```yml
|
@@ -524,7 +560,7 @@ For XSalsa20, use the appropriate [Libsodium library](https://libsodium.gitbook.
|
|
524
560
|
|
525
561
|
## Migrating from Another Library
|
526
562
|
|
527
|
-
Lockbox makes it easy to migrate from another library. The example below uses `attr_encrypted` but the same approach should work for any library.
|
563
|
+
Lockbox makes it easy to migrate from another library without downtime. The example below uses `attr_encrypted` but the same approach should work for any library.
|
528
564
|
|
529
565
|
Let’s suppose your model looks like this:
|
530
566
|
|
@@ -538,7 +574,7 @@ end
|
|
538
574
|
Create a migration with:
|
539
575
|
|
540
576
|
```ruby
|
541
|
-
class MigrateToLockbox < ActiveRecord::Migration[
|
577
|
+
class MigrateToLockbox < ActiveRecord::Migration[6.0]
|
542
578
|
def change
|
543
579
|
add_column :users, :name_ciphertext, :text
|
544
580
|
add_column :users, :email_ciphertext, :text
|
@@ -571,7 +607,7 @@ end
|
|
571
607
|
Then remove the previous gem from your Gemfile and drop its columns.
|
572
608
|
|
573
609
|
```ruby
|
574
|
-
class RemovePreviousEncryptedColumns < ActiveRecord::Migration[
|
610
|
+
class RemovePreviousEncryptedColumns < ActiveRecord::Migration[6.0]
|
575
611
|
def change
|
576
612
|
remove_column :users, :encrypted_name, :text
|
577
613
|
remove_column :users, :encrypted_name_iv, :text
|
@@ -639,3 +675,12 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
|
|
639
675
|
- Fix bugs and [submit pull requests](https://github.com/ankane/lockbox/pulls)
|
640
676
|
- Write, clarify, or fix documentation
|
641
677
|
- Suggest or add new features
|
678
|
+
|
679
|
+
To get started with development and testing:
|
680
|
+
|
681
|
+
```sh
|
682
|
+
git clone https://github.com/ankane/lockbox.git
|
683
|
+
cd lockbox
|
684
|
+
bundle install
|
685
|
+
bundle exec rake test
|
686
|
+
```
|
data/lib/lockbox.rb
CHANGED
data/lib/lockbox/model.rb
CHANGED
@@ -104,10 +104,13 @@ class Lockbox
|
|
104
104
|
@lockbox_attributes[original_name] = options.merge(encode: encode)
|
105
105
|
|
106
106
|
if @lockbox_attributes.size == 1
|
107
|
+
# use same approach as activerecord serialization
|
107
108
|
def serializable_hash(options = nil)
|
108
109
|
options = options.try(:dup) || {}
|
110
|
+
|
109
111
|
options[:except] = Array(options[:except])
|
110
|
-
options[:except] += self.class.lockbox_attributes.
|
112
|
+
options[:except] += self.class.lockbox_attributes.flat_map { |_, v| [v[:attribute], v[:encrypted_attribute]] }
|
113
|
+
|
111
114
|
super(options)
|
112
115
|
end
|
113
116
|
|
@@ -151,6 +154,10 @@ class Lockbox
|
|
151
154
|
|
152
155
|
if respond_to?(:attribute)
|
153
156
|
attribute name, attribute_type
|
157
|
+
|
158
|
+
define_method("#{name}?") do
|
159
|
+
send("#{encrypted_attribute}?")
|
160
|
+
end
|
154
161
|
else
|
155
162
|
m = Module.new do
|
156
163
|
define_method("#{name}=") do |val|
|
@@ -183,45 +190,6 @@ class Lockbox
|
|
183
190
|
define_method("#{name}=") do |message|
|
184
191
|
original_message = message
|
185
192
|
|
186
|
-
unless message.nil?
|
187
|
-
case options[:type]
|
188
|
-
when :boolean
|
189
|
-
message = ActiveRecord::Type::Boolean.new.serialize(message)
|
190
|
-
message = nil if message == "" # for Active Record < 5.2
|
191
|
-
message = message ? "t" : "f" unless message.nil?
|
192
|
-
when :date
|
193
|
-
message = ActiveRecord::Type::Date.new.serialize(message)
|
194
|
-
# strftime should be more stable than to_s(:db)
|
195
|
-
message = message.strftime("%Y-%m-%d") unless message.nil?
|
196
|
-
when :datetime
|
197
|
-
message = ActiveRecord::Type::DateTime.new.serialize(message)
|
198
|
-
message = nil unless message.respond_to?(:iso8601) # for Active Record < 5.2
|
199
|
-
message = message.iso8601(9) unless message.nil?
|
200
|
-
when :time
|
201
|
-
message = ActiveRecord::Type::Time.new.serialize(message)
|
202
|
-
message = nil unless message.respond_to?(:strftime)
|
203
|
-
message = message.strftime("%H:%M:%S.%N") unless message.nil?
|
204
|
-
message
|
205
|
-
when :integer
|
206
|
-
message = ActiveRecord::Type::Integer.new(limit: 8).serialize(message)
|
207
|
-
message = 0 if message.nil?
|
208
|
-
# signed 64-bit integer, big endian
|
209
|
-
message = [message].pack("q>")
|
210
|
-
when :float
|
211
|
-
message = ActiveRecord::Type::Float.new.serialize(message)
|
212
|
-
# double precision, big endian
|
213
|
-
message = [message].pack("G") unless message.nil?
|
214
|
-
when :string, :binary
|
215
|
-
# do nothing
|
216
|
-
# encrypt will convert to binary
|
217
|
-
else
|
218
|
-
type = (self.class.try(:attribute_types) || {})[name.to_s]
|
219
|
-
if type && type.is_a?(ActiveRecord::Type::Serialized)
|
220
|
-
message = type.serialize(message)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
193
|
# decrypt first for dirty tracking
|
226
194
|
# don't raise error if can't decrypt previous
|
227
195
|
begin
|
@@ -230,13 +198,8 @@ class Lockbox
|
|
230
198
|
nil
|
231
199
|
end
|
232
200
|
|
233
|
-
ciphertext
|
234
|
-
|
235
|
-
message
|
236
|
-
else
|
237
|
-
self.class.send(class_method_name, message, context: self)
|
238
|
-
end
|
239
|
-
|
201
|
+
# set ciphertext
|
202
|
+
ciphertext = self.class.send(class_method_name, message, context: self)
|
240
203
|
send("#{encrypted_attribute}=", ciphertext)
|
241
204
|
|
242
205
|
super(original_message)
|
@@ -305,9 +268,53 @@ class Lockbox
|
|
305
268
|
# for fixtures
|
306
269
|
define_singleton_method class_method_name do |message, **opts|
|
307
270
|
table = respond_to?(:table_name) ? table_name : collection_name.to_s
|
308
|
-
|
309
|
-
|
310
|
-
|
271
|
+
|
272
|
+
unless message.nil?
|
273
|
+
case options[:type]
|
274
|
+
when :boolean
|
275
|
+
message = ActiveRecord::Type::Boolean.new.serialize(message)
|
276
|
+
message = nil if message == "" # for Active Record < 5.2
|
277
|
+
message = message ? "t" : "f" unless message.nil?
|
278
|
+
when :date
|
279
|
+
message = ActiveRecord::Type::Date.new.serialize(message)
|
280
|
+
# strftime should be more stable than to_s(:db)
|
281
|
+
message = message.strftime("%Y-%m-%d") unless message.nil?
|
282
|
+
when :datetime
|
283
|
+
message = ActiveRecord::Type::DateTime.new.serialize(message)
|
284
|
+
message = nil unless message.respond_to?(:iso8601) # for Active Record < 5.2
|
285
|
+
message = message.iso8601(9) unless message.nil?
|
286
|
+
when :time
|
287
|
+
message = ActiveRecord::Type::Time.new.serialize(message)
|
288
|
+
message = nil unless message.respond_to?(:strftime)
|
289
|
+
message = message.strftime("%H:%M:%S.%N") unless message.nil?
|
290
|
+
message
|
291
|
+
when :integer
|
292
|
+
message = ActiveRecord::Type::Integer.new(limit: 8).serialize(message)
|
293
|
+
message = 0 if message.nil?
|
294
|
+
# signed 64-bit integer, big endian
|
295
|
+
message = [message].pack("q>")
|
296
|
+
when :float
|
297
|
+
message = ActiveRecord::Type::Float.new.serialize(message)
|
298
|
+
# double precision, big endian
|
299
|
+
message = [message].pack("G") unless message.nil?
|
300
|
+
when :string, :binary
|
301
|
+
# do nothing
|
302
|
+
# encrypt will convert to binary
|
303
|
+
else
|
304
|
+
type = (try(:attribute_types) || {})[name.to_s]
|
305
|
+
if type && type.is_a?(ActiveRecord::Type::Serialized)
|
306
|
+
message = type.serialize(message)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
if message.nil? || (message == "" && !options[:padding])
|
312
|
+
message
|
313
|
+
else
|
314
|
+
ciphertext = Lockbox::Utils.build_box(opts[:context], options, table, encrypted_attribute).encrypt(message)
|
315
|
+
ciphertext = Base64.strict_encode64(ciphertext) if encode
|
316
|
+
ciphertext
|
317
|
+
end
|
311
318
|
end
|
312
319
|
end
|
313
320
|
end
|
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.2.
|
4
|
+
version: 0.2.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: 2019-
|
11
|
+
date: 2019-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -218,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
218
218
|
- !ruby/object:Gem::Version
|
219
219
|
version: '0'
|
220
220
|
requirements: []
|
221
|
-
rubygems_version: 3.0.
|
221
|
+
rubygems_version: 3.0.3
|
222
222
|
signing_key:
|
223
223
|
specification_version: 4
|
224
224
|
summary: Modern encryption for Rails
|