blind_index 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 +4 -0
- data/README.md +67 -3
- data/lib/blind_index/extensions.rb +2 -2
- data/lib/blind_index/model.rb +6 -1
- data/lib/blind_index/version.rb +1 -1
- metadata +6 -14
- data/.gitignore +0 -9
- data/.travis.yml +0 -14
- data/Gemfile +0 -4
- data/Rakefile +0 -56
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/blind_index.gemspec +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26d5a803099fa8b408065a43056697f24eaf10a89c6a778979e5bdd8d54bbb5e
|
4
|
+
data.tar.gz: '0288069afcdd54f3f3917ef25177550bd3c912333aca346d1ae77d0d237eb5ce'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f062a2b9d1aa2d251dd38b6c815423afa146a34df0825d655bd9ac0ea666af9d0382d958995c7899e16a729b15e7e3d696d661485a246220e93bade67104641
|
7
|
+
data.tar.gz: 1478bb3716c6ad099e42ed95b286d7aa5a13c6be7f75d4ec6e7d5c82898c95d1fc7db2537d53c6daa5754ad398579bca5e924a60551423402e064f24b52ee2ff
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Securely search encrypted database fields
|
|
4
4
|
|
5
5
|
Designed for use with [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted)
|
6
6
|
|
7
|
-
Here’s a [full example](https://
|
7
|
+
Here’s a [full example](https://ankane.org/securing-user-emails-in-rails) of how to use it with Devise
|
8
8
|
|
9
9
|
[](https://travis-ci.org/ankane/blind_index)
|
10
10
|
|
@@ -42,7 +42,7 @@ class User < ApplicationRecord
|
|
42
42
|
end
|
43
43
|
```
|
44
44
|
|
45
|
-
We use environment variables to store the keys as hex-encoded strings ([dotenv](https://github.com/bkeepers/dotenv) is great for this). *Do not commit them to source control.* Generate one key for encryption and one key for hashing. You can generate keys in the Rails console with:
|
45
|
+
We use environment variables to store the keys as hex-encoded strings ([dotenv](https://github.com/bkeepers/dotenv) is great for this). [Here’s an explanation](https://ankane.org/encryption-keys) of why `pack` is used. *Do not commit them to source control.* Generate one key for encryption and one key for hashing. You can generate keys in the Rails console with:
|
46
46
|
|
47
47
|
```ruby
|
48
48
|
SecureRandom.hex(32)
|
@@ -118,12 +118,36 @@ class User < ApplicationRecord
|
|
118
118
|
end
|
119
119
|
```
|
120
120
|
|
121
|
+
*Requires ActiveRecord 5.1+*
|
122
|
+
|
123
|
+
## Multiple Columns
|
124
|
+
|
125
|
+
You can also use virtual attributes to index data from multiple columns:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
class User < ApplicationRecord
|
129
|
+
attribute :initials
|
130
|
+
|
131
|
+
# must come before blind_index method
|
132
|
+
before_validation :set_initials, if: -> { changes.key?(:first_name) || changes.key?(:last_name) }
|
133
|
+
blind_index :initials, ...
|
134
|
+
|
135
|
+
def set_initials
|
136
|
+
self.initials = "#{first_name[0]}#{last_name[0]}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
*Requires ActiveRecord 5.1+*
|
142
|
+
|
121
143
|
## Fixtures
|
122
144
|
|
123
|
-
You can use blind indexes in fixtures with:
|
145
|
+
You can use encrypted attributes and blind indexes in fixtures with:
|
124
146
|
|
125
147
|
```yml
|
126
148
|
test_user:
|
149
|
+
encrypted_email: <%= User.encrypt_email("test@example.org", iv: Base64.decode64("0000000000000000")) %>
|
150
|
+
encrypted_email_iv: "0000000000000000"
|
127
151
|
encrypted_email_bidx: <%= User.compute_email_bidx("test@example.org").inspect %>
|
128
152
|
```
|
129
153
|
|
@@ -179,6 +203,46 @@ class User < ApplicationRecord
|
|
179
203
|
end
|
180
204
|
```
|
181
205
|
|
206
|
+
## Key Rotation
|
207
|
+
|
208
|
+
To rotate keys without downtime, add a new column:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
add_column :users, :encrypted_email_v2_bidx, :string
|
212
|
+
add_index :users, :encrypted_email_v2_bidx
|
213
|
+
```
|
214
|
+
|
215
|
+
And add to your model
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
class User < ApplicationRecord
|
219
|
+
blind_index :email, key: [ENV["EMAIL_BLIND_INDEX_KEY"]].pack("H*")
|
220
|
+
blind_index :email_v2, attribute: :email, key: [ENV["EMAIL_V2_BLIND_INDEX_KEY"]].pack("H*")
|
221
|
+
end
|
222
|
+
```
|
223
|
+
|
224
|
+
Backfill the data
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
User.find_each do |user|
|
228
|
+
user.compute_email_v2_bidx
|
229
|
+
user.save!
|
230
|
+
end
|
231
|
+
```
|
232
|
+
|
233
|
+
Then update your model
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
class User < ApplicationRecord
|
237
|
+
blind_index :email, bidx_attribute: :encrypted_email_v2_bidx, key: [ENV["EMAIL_V2_BLIND_INDEX_KEY"]].pack("H*")
|
238
|
+
|
239
|
+
# remove this line after dropping column
|
240
|
+
self.ignored_columns = ["encrypted_email_bidx"]
|
241
|
+
end
|
242
|
+
```
|
243
|
+
|
244
|
+
Finally, drop the old column.
|
245
|
+
|
182
246
|
## Reference
|
183
247
|
|
184
248
|
By default, blind indexes are encoded in Base64. Set a different encoding with:
|
@@ -6,7 +6,7 @@ module BlindIndex
|
|
6
6
|
new_hash = super
|
7
7
|
if has_blind_indexes?
|
8
8
|
hash.each do |key, _|
|
9
|
-
if (bi = klass.blind_indexes[key]) && !new_hash[key].is_a?(ActiveRecord::StatementCache::Substitute)
|
9
|
+
if key.respond_to?(:to_sym) && (bi = klass.blind_indexes[key.to_sym]) && !new_hash[key].is_a?(ActiveRecord::StatementCache::Substitute)
|
10
10
|
new_hash[bi[:bidx_attribute]] = BlindIndex.generate_bidx(new_hash.delete(key), bi)
|
11
11
|
end
|
12
12
|
end
|
@@ -29,7 +29,7 @@ module BlindIndex
|
|
29
29
|
new_hash = super
|
30
30
|
if has_blind_indexes?(klass)
|
31
31
|
hash.each do |key, _|
|
32
|
-
if (bi = klass.blind_indexes[key]) && !new_hash[key].is_a?(ActiveRecord::StatementCache::Substitute)
|
32
|
+
if key.respond_to?(:to_sym) && (bi = klass.blind_indexes[key.to_sym]) && !new_hash[key].is_a?(ActiveRecord::StatementCache::Substitute)
|
33
33
|
new_hash[bi[:bidx_attribute]] = BlindIndex.generate_bidx(new_hash.delete(key), bi)
|
34
34
|
end
|
35
35
|
end
|
data/lib/blind_index/model.rb
CHANGED
@@ -49,7 +49,12 @@ module BlindIndex
|
|
49
49
|
end
|
50
50
|
|
51
51
|
if callback
|
52
|
-
|
52
|
+
if ActiveRecord::VERSION::STRING >= "5.1"
|
53
|
+
before_validation method_name, if: :"will_save_change_to_#{attribute}?"
|
54
|
+
else
|
55
|
+
before_validation method_name, if: -> { changes.key?(attribute.to_s) }
|
56
|
+
end
|
57
|
+
|
53
58
|
end
|
54
59
|
|
55
60
|
# use include so user can override
|
data/lib/blind_index/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blind_index
|
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
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -151,22 +151,14 @@ dependencies:
|
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
153
|
description:
|
154
|
-
email:
|
155
|
-
- andrew@chartkick.com
|
154
|
+
email: andrew@chartkick.com
|
156
155
|
executables: []
|
157
156
|
extensions: []
|
158
157
|
extra_rdoc_files: []
|
159
158
|
files:
|
160
|
-
- ".gitignore"
|
161
|
-
- ".travis.yml"
|
162
159
|
- CHANGELOG.md
|
163
|
-
- Gemfile
|
164
160
|
- LICENSE.txt
|
165
161
|
- README.md
|
166
|
-
- Rakefile
|
167
|
-
- bin/console
|
168
|
-
- bin/setup
|
169
|
-
- blind_index.gemspec
|
170
162
|
- lib/blind_index.rb
|
171
163
|
- lib/blind_index/extensions.rb
|
172
164
|
- lib/blind_index/model.rb
|
@@ -183,7 +175,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
175
|
requirements:
|
184
176
|
- - ">="
|
185
177
|
- !ruby/object:Gem::Version
|
186
|
-
version: '
|
178
|
+
version: '2.2'
|
187
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
180
|
requirements:
|
189
181
|
- - ">="
|
@@ -191,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
183
|
version: '0'
|
192
184
|
requirements: []
|
193
185
|
rubyforge_project:
|
194
|
-
rubygems_version: 2.7.
|
186
|
+
rubygems_version: 2.7.7
|
195
187
|
signing_key:
|
196
188
|
specification_version: 4
|
197
189
|
summary: Securely search encrypted database fields
|
data/.gitignore
DELETED
data/.travis.yml
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm: 2.4.2
|
3
|
-
gemfile:
|
4
|
-
- Gemfile
|
5
|
-
- test/gemfiles/activerecord51.gemfile
|
6
|
-
- test/gemfiles/activerecord50.gemfile
|
7
|
-
- test/gemfiles/activerecord42.gemfile
|
8
|
-
sudo: false
|
9
|
-
before_install: gem install bundler
|
10
|
-
script: bundle exec rake test
|
11
|
-
notifications:
|
12
|
-
email:
|
13
|
-
on_success: never
|
14
|
-
on_failure: change
|
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
require "rake/testtask"
|
3
|
-
|
4
|
-
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs << "test"
|
6
|
-
t.libs << "lib"
|
7
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
8
|
-
t.warning = false
|
9
|
-
end
|
10
|
-
|
11
|
-
task default: :test
|
12
|
-
|
13
|
-
namespace :benchmark do
|
14
|
-
task :algorithms do
|
15
|
-
require "securerandom"
|
16
|
-
require "benchmark/ips"
|
17
|
-
require "blind_index"
|
18
|
-
require "scrypt"
|
19
|
-
require "argon2"
|
20
|
-
|
21
|
-
key = SecureRandom.random_bytes(32)
|
22
|
-
value = "secret"
|
23
|
-
|
24
|
-
Benchmark.ips do |x|
|
25
|
-
x.report("pbkdf2_hmac") { BlindIndex.generate_bidx(value, key: key, algorithm: :pbkdf2_hmac) }
|
26
|
-
x.report("scrypt") { BlindIndex.generate_bidx(value, key: key, algorithm: :scrypt) }
|
27
|
-
x.report("argon2") { BlindIndex.generate_bidx(value, key: key, algorithm: :argon2) }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
task :queries do
|
32
|
-
require "benchmark/ips"
|
33
|
-
require "active_record"
|
34
|
-
require "blind_index"
|
35
|
-
|
36
|
-
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
37
|
-
|
38
|
-
ActiveRecord::Migration.create_table :users do
|
39
|
-
end
|
40
|
-
|
41
|
-
ActiveRecord::Migration.create_table :cities do
|
42
|
-
end
|
43
|
-
|
44
|
-
class User < ActiveRecord::Base
|
45
|
-
blind_index :email
|
46
|
-
end
|
47
|
-
|
48
|
-
class City < ActiveRecord::Base
|
49
|
-
end
|
50
|
-
|
51
|
-
Benchmark.ips do |x|
|
52
|
-
x.report("no index") { City.where(id: 1).first }
|
53
|
-
x.report("index") { User.where(id: 1).first }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "blind_index"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/blind_index.gemspec
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "blind_index/version"
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "blind_index"
|
8
|
-
spec.version = BlindIndex::VERSION
|
9
|
-
spec.authors = ["Andrew Kane"]
|
10
|
-
spec.email = ["andrew@chartkick.com"]
|
11
|
-
|
12
|
-
spec.summary = "Securely search encrypted database fields"
|
13
|
-
spec.homepage = "https://github.com/ankane/blind_index"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
-
f.match(%r{^(test|spec|features)/})
|
18
|
-
end
|
19
|
-
spec.bindir = "exe"
|
20
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
-
spec.require_paths = ["lib"]
|
22
|
-
|
23
|
-
spec.add_dependency "activesupport", ">= 4.2"
|
24
|
-
|
25
|
-
spec.add_development_dependency "bundler"
|
26
|
-
spec.add_development_dependency "rake"
|
27
|
-
spec.add_development_dependency "minitest"
|
28
|
-
spec.add_development_dependency "attr_encrypted"
|
29
|
-
spec.add_development_dependency "activerecord"
|
30
|
-
spec.add_development_dependency "sqlite3"
|
31
|
-
spec.add_development_dependency "scrypt"
|
32
|
-
spec.add_development_dependency "argon2"
|
33
|
-
spec.add_development_dependency "benchmark-ips"
|
34
|
-
end
|