blind_index 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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