blind_index 0.1.1 → 0.2.0
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/.travis.yml +1 -0
- data/CHANGELOG.md +6 -0
- data/README.md +21 -14
- data/blind_index.gemspec +1 -1
- data/lib/blind_index/extensions.rb +26 -0
- data/lib/blind_index/model.rb +14 -1
- data/lib/blind_index/version.rb +1 -1
- data/lib/blind_index.rb +14 -7
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a2f034adc1842667c23445f308df57c7f799d802190d570985037955eedab8d
|
4
|
+
data.tar.gz: 7461ef87a66f92771aa4101624e5a025f4a3548a16b8c32b997371629542ee7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 343a9b809e3109bbc66bbbc842840837383c22c1707cb2a143949989b55f5230db3b7c8563f78db03b1edf54a2606f94bc0a68ec4891acfe25d571fef6ac3a1c
|
7
|
+
data.tar.gz: 37083bfe331da9a1c7861009907a43e35a71d16db4c0cd1101af1033d1d023c305c4d47aee0e4ec17952c3ebc12c3d2fbda6cc48d284a231acd777fcfffa6cda
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Designed for use with [attr_encrypted](https://github.com/attr-encrypted/attr_en
|
|
8
8
|
|
9
9
|
## How It Works
|
10
10
|
|
11
|
-
|
11
|
+
We use [this approach](https://www.sitepoint.com/how-to-search-on-securely-encrypted-database-fields/) by Scott Arciszewski. To summarize, we compute a keyed hash of the sensitive data and store it in a column. To query, we apply the keyed hash function (PBKDF2-HMAC-SHA256) to the value we’re searching and then perform a database search. This results in performant queries for equality operations, while keeping the data secure from those without the key.
|
12
12
|
|
13
13
|
## Getting Started
|
14
14
|
|
@@ -23,31 +23,30 @@ Add columns for the encrypted data and the blind index
|
|
23
23
|
|
24
24
|
```ruby
|
25
25
|
# encrypted data
|
26
|
-
add_column :users, :encrypted_email, :
|
27
|
-
add_column :users, :encrypted_email_iv, :
|
26
|
+
add_column :users, :encrypted_email, :string
|
27
|
+
add_column :users, :encrypted_email_iv, :string
|
28
28
|
|
29
29
|
# blind index
|
30
|
-
add_column :users, :encrypted_email_bidx, :
|
30
|
+
add_column :users, :encrypted_email_bidx, :string
|
31
31
|
add_index :users, :encrypted_email_bidx
|
32
32
|
```
|
33
33
|
|
34
|
-
Generate one key for encryption and one key for hashing and set them in your environment ([dotenv](https://github.com/bkeepers/dotenv) is great for this). For development, you can use these:
|
35
|
-
|
36
|
-
```sh
|
37
|
-
EMAIL_ENCRYPTION_KEY=00000000000000000000000000000000
|
38
|
-
EMAIL_BLIND_INDEX_KEY=99999999999999999999999999999999
|
39
|
-
```
|
40
|
-
|
41
34
|
And add to your model
|
42
35
|
|
43
36
|
```ruby
|
44
37
|
class User < ApplicationRecord
|
45
38
|
attr_encrypted :email, key: ENV["EMAIL_ENCRYPTION_KEY"]
|
46
|
-
|
47
39
|
blind_index :email, key: ENV["EMAIL_BLIND_INDEX_KEY"]
|
48
40
|
end
|
49
41
|
```
|
50
42
|
|
43
|
+
We use environment variables to store the keys ([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. For development, you can use these:
|
44
|
+
|
45
|
+
```sh
|
46
|
+
EMAIL_ENCRYPTION_KEY=00000000000000000000000000000000
|
47
|
+
EMAIL_BLIND_INDEX_KEY=99999999999999999999999999999999
|
48
|
+
```
|
49
|
+
|
51
50
|
And query away
|
52
51
|
|
53
52
|
```ruby
|
@@ -81,7 +80,7 @@ end
|
|
81
80
|
You may want multiple blind indexes for an attribute. To do this, add another column:
|
82
81
|
|
83
82
|
```ruby
|
84
|
-
add_column :users, :encrypted_email_ci_bidx, :
|
83
|
+
add_column :users, :encrypted_email_ci_bidx, :string
|
85
84
|
add_index :users, :encrypted_email_ci_bidx
|
86
85
|
```
|
87
86
|
|
@@ -119,7 +118,6 @@ If you don’t need to store the original value (for instance, when just checkin
|
|
119
118
|
```ruby
|
120
119
|
class User < ApplicationRecord
|
121
120
|
attribute :email
|
122
|
-
|
123
121
|
blind_index :email, ...
|
124
122
|
end
|
125
123
|
```
|
@@ -136,3 +134,12 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
|
|
136
134
|
- Fix bugs and [submit pull requests](https://github.com/ankane/blind_index/pulls)
|
137
135
|
- Write, clarify, or fix documentation
|
138
136
|
- Suggest or add new features
|
137
|
+
|
138
|
+
To get started with development and testing:
|
139
|
+
|
140
|
+
```sh
|
141
|
+
git clone https://github.com/ankane/blind_index.git
|
142
|
+
cd blind_index
|
143
|
+
bundle install
|
144
|
+
rake test
|
145
|
+
```
|
data/blind_index.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.add_dependency "activesupport", ">=
|
23
|
+
spec.add_dependency "activesupport", ">= 4.2"
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler"
|
26
26
|
spec.add_development_dependency "rake"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module BlindIndex
|
2
2
|
module Extensions
|
3
|
+
# ActiveRecord 5.0+
|
3
4
|
module TableMetadata
|
4
5
|
def resolve_column_aliases(hash)
|
5
6
|
new_hash = super
|
@@ -22,6 +23,31 @@ module BlindIndex
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
26
|
+
# ActiveRecord 4.2
|
27
|
+
module PredicateBuilder
|
28
|
+
def resolve_column_aliases(klass, hash)
|
29
|
+
new_hash = super
|
30
|
+
if has_blind_indexes?(klass)
|
31
|
+
hash.each do |key, _|
|
32
|
+
if (bi = klass.blind_indexes[key])
|
33
|
+
new_hash[bi[:bidx_attribute]] = BlindIndex.generate_bidx(new_hash.delete(key), bi)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
new_hash
|
38
|
+
end
|
39
|
+
|
40
|
+
@@blind_index_cache = {}
|
41
|
+
|
42
|
+
# memoize for performance
|
43
|
+
def has_blind_indexes?(klass)
|
44
|
+
if @@blind_index_cache[klass].nil?
|
45
|
+
@@blind_index_cache[klass] = klass.respond_to?(:blind_indexes)
|
46
|
+
end
|
47
|
+
@@blind_index_cache[klass]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
25
51
|
module UniquenessValidator
|
26
52
|
if ActiveRecord::VERSION::STRING >= "5.2"
|
27
53
|
def build_relation(klass, attribute, value)
|
data/lib/blind_index/model.rb
CHANGED
@@ -13,7 +13,7 @@ module BlindIndex
|
|
13
13
|
class << self
|
14
14
|
def blind_indexes
|
15
15
|
@blind_indexes ||= {}
|
16
|
-
end unless
|
16
|
+
end unless method_defined?(:blind_indexes)
|
17
17
|
end
|
18
18
|
|
19
19
|
raise BlindIndex::Error, "Duplicate blind index: #{name}" if blind_indexes[name]
|
@@ -33,6 +33,19 @@ module BlindIndex
|
|
33
33
|
if callback
|
34
34
|
before_validation method_name, if: -> { changes.key?(attribute.to_s) }
|
35
35
|
end
|
36
|
+
|
37
|
+
# use include so user can override
|
38
|
+
include InstanceMethods if blind_indexes.size == 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module InstanceMethods
|
44
|
+
def read_attribute_for_validation(key)
|
45
|
+
if (bi = self.class.blind_indexes[key])
|
46
|
+
send(bi[:attribute])
|
47
|
+
else
|
48
|
+
super
|
36
49
|
end
|
37
50
|
end
|
38
51
|
end
|
data/lib/blind_index/version.rb
CHANGED
data/lib/blind_index.rb
CHANGED
@@ -16,19 +16,26 @@ module BlindIndex
|
|
16
16
|
# apply expression
|
17
17
|
value = expression.call(value) if expression
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
unless value.nil?
|
20
|
+
# generate hash
|
21
|
+
digest = OpenSSL::Digest::SHA256.new
|
22
|
+
value = OpenSSL::PKCS5.pbkdf2_hmac(value.to_s, key, iterations, digest.digest_length, digest)
|
23
|
+
|
24
|
+
# encode
|
25
|
+
[value].pack("m")
|
26
|
+
end
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
30
|
ActiveSupport.on_load(:active_record) do
|
29
31
|
require "blind_index/extensions"
|
30
32
|
extend BlindIndex::Model
|
31
|
-
|
33
|
+
|
34
|
+
if defined?(ActiveRecord::TableMetadata)
|
35
|
+
ActiveRecord::TableMetadata.prepend(BlindIndex::Extensions::TableMetadata)
|
36
|
+
else
|
37
|
+
ActiveRecord::PredicateBuilder.singleton_class.prepend(BlindIndex::Extensions::PredicateBuilder)
|
38
|
+
end
|
32
39
|
|
33
40
|
unless ActiveRecord::VERSION::STRING.start_with?("5.1.")
|
34
41
|
ActiveRecord::Validations::UniquenessValidator.prepend(BlindIndex::Extensions::UniquenessValidator)
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '4.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '4.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|