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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 370f6b1f09b18d3031f83b76785b8604e7ea8efa553a74d205ca874505abf26d
4
- data.tar.gz: dd69a591d88afec3cb63433e78cf9d443828b544fe47c965cfbaf65965c4047e
3
+ metadata.gz: 3a2f034adc1842667c23445f308df57c7f799d802190d570985037955eedab8d
4
+ data.tar.gz: 7461ef87a66f92771aa4101624e5a025f4a3548a16b8c32b997371629542ee7a
5
5
  SHA512:
6
- metadata.gz: b3e1e1c4a05f421a65039197e8e7ce4db8057d06529c7b01ba69395c207b77ef3bfbf3b8c5bcc208818d96a6dd78c0d1ddfd42e0ceb525e348c390647014b400
7
- data.tar.gz: 017240cd3b9c125c5a9d455085825bee6f985dff4db129e0adb54dd032ef5d74281267f2fd39b74f38b4043c04798a87c3e1d79e71d29ce3c093ee95fd3d0060
6
+ metadata.gz: 343a9b809e3109bbc66bbbc842840837383c22c1707cb2a143949989b55f5230db3b7c8563f78db03b1edf54a2606f94bc0a68ec4891acfe25d571fef6ac3a1c
7
+ data.tar.gz: 37083bfe331da9a1c7861009907a43e35a71d16db4c0cd1101af1033d1d023c305c4d47aee0e4ec17952c3ebc12c3d2fbda6cc48d284a231acd777fcfffa6cda
data/.travis.yml CHANGED
@@ -4,6 +4,7 @@ gemfile:
4
4
  - Gemfile
5
5
  - test/gemfiles/activerecord51.gemfile
6
6
  - test/gemfiles/activerecord50.gemfile
7
+ - test/gemfiles/activerecord42.gemfile
7
8
  sudo: false
8
9
  before_install: gem install bundler
9
10
  script: bundle exec rake test
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.2.0
2
+
3
+ - Added support for ActiveRecord 4.2
4
+ - Improved validation support when multiple blind indexes
5
+ - Fixed `nil` handling
6
+
1
7
  ## 0.1.1
2
8
 
3
9
  - Added support for ActiveRecord 5.2
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
- This project uses [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.
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, :text
27
- add_column :users, :encrypted_email_iv, :text
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, :text
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, :text
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", ">= 5"
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)
@@ -13,7 +13,7 @@ module BlindIndex
13
13
  class << self
14
14
  def blind_indexes
15
15
  @blind_indexes ||= {}
16
- end unless respond_to?(:blind_indexes)
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
@@ -1,3 +1,3 @@
1
1
  module BlindIndex
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
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
- # generate hash
20
- digest = OpenSSL::Digest::SHA256.new
21
- value = OpenSSL::PKCS5.pbkdf2_hmac(value.to_s, key, iterations, digest.digest_length, digest)
22
-
23
- # encode
24
- [value].pack("m")
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
- ActiveRecord::TableMetadata.prepend(BlindIndex::Extensions::TableMetadata)
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.1.1
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-04-10 00:00:00.000000000 Z
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: '5'
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: '5'
26
+ version: '4.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement