encrypted_search_attributes 1.0.1 → 1.1.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,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MGE2MWE3OGJkYjIyOGEyNTgyMDdjNTQ4YWUzYmM3MjhkMzkzNDRkNA==
5
- data.tar.gz: !binary |-
6
- YWQ3YzYzMzc5ZjQ0Y2I5MmU0ZWE1NjRhMjM1MzY5NWE4MDM4NTEzNg==
2
+ SHA1:
3
+ metadata.gz: 71c31041e7631bfc6e189c0b2b88fff33ed376f6
4
+ data.tar.gz: af0c66f1efec431a32218112b929fd57661b2ba7
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- OTExZDViYzQ0NzI1NzAyOTBiNzJlMzUyMmZhYTg2ZGJjNTA5MDFiYTk4ODZj
10
- ZDBhZTMwMzZmNzMwN2FlZTNhYzkwYzE3Y2FiMTdiZjA2Mzg3NGY5MzA3NTYz
11
- NDhhYjJkMDAxMzVkMGU5ZTViMTM3MGMyM2E1NGU5NGNmNjYyYTU=
12
- data.tar.gz: !binary |-
13
- MmJmMTUzOTMzYjI2Y2U2ZTFhNDM2ZGVhZjdjYTE5M2EzNGRhYmUwM2I5MTEw
14
- OTAxMGMwNWM3OWUwYWM5MTFjODJiMDkyMTQxM2YwZDEwMTZiNGQyMjk5M2Q3
15
- ZWI2NGI0M2ZlZjdlMzYyMjQ3MzY0OTViYzkyNGJmNzc0ZDE2NmE=
6
+ metadata.gz: 64acc8baadd3c6bf1976ec71455b8db26a3d7d35b69ae56c0e75b63902e9fc636a482b16e442194e352df83c42bafca0a1eded48800be4c5cb93251f39953f28
7
+ data.tar.gz: d1ba0cde85f8fcf68f9e9d8d19dd55eb631a1d03e5fbf9238b28a380633b71def5d58da66d8ee88830f559767638691d36eeec8b4a9384dfc5bdef123557b6f7
data/README.md CHANGED
@@ -2,11 +2,13 @@
2
2
 
3
3
  Auto populates encrypted fields that are designed for searching
4
4
 
5
- Encrypting a field makes it very difficult to perform a case insensitive search for the columns data. This gem normalizes the text before encrypted it and storing it in a search column. The current normalization method is to convert the text to all lowercase.
5
+ Encrypting a field makes it very difficult to perform a case insensitive search for the columns data. This gem normalizes the text before encrypted it and storing it in a search column. The default normalization method is to convert the text to all lowercase, but you can specify your own normalization method.
6
6
 
7
7
  This gem is intended to be used with the symmetric-encryption gem. It assumes that a `encrypted_search_attribute` column exists for the encrypted attribute.
8
8
 
9
- ## Example
9
+ ## Examples
10
+
11
+ ### Using the default normalization method
10
12
 
11
13
  Let's assume we have the following ActiveRecord model defined.
12
14
 
@@ -26,6 +28,38 @@ This would require the database schema to look something like this.
26
28
  end
27
29
  ```
28
30
 
31
+ ### Specifying a custom normalization method
32
+
33
+ You can specify custom normalizations in a couple of different ways
34
+
35
+ #### Procs
36
+
37
+ You can specify a proc that gets called to perform the normalization. This works well if you only have one field that you need to override the normalization for.
38
+
39
+ ```ruby
40
+ class Widget < ActiveRecord::Base
41
+ attr_encrypted :name
42
+ attr_encrypted_search :name,
43
+ normalize: ->(unencrypted_value) { enencrypted_value.to_s.downcase.gsub('.', '') }
44
+ end
45
+ ```
46
+
47
+ #### Symbol referencing a method
48
+
49
+ ```ruby
50
+ class Widget < ActiveRecord::Base
51
+ attr_encrypted :name
52
+ attr_encrypted_search :name,
53
+ normalize: :normalize_search_value
54
+
55
+ private
56
+
57
+ def normalize_search_value(unencypted_value)
58
+ enencrypted_value.to_s.downcase.gsub('.', '')
59
+ end
60
+ end
61
+ ```
62
+
29
63
  ## Installation
30
64
 
31
65
  Add this line to your application's Gemfile:
@@ -40,13 +74,9 @@ Or install it yourself as:
40
74
 
41
75
  $ gem install encrypted_search_attributes
42
76
 
43
- ## Usage
44
-
45
- TODO: Write usage instructions here
46
-
47
77
  ## Contributing
48
78
 
49
- 1. Fork it ( http://github.com/mscottford/encrypted_search_attributes/fork )
79
+ 1. Fork it ( http://github.com/corgibytes/encrypted_search_attributes/fork )
50
80
  2. Create your feature branch (`git checkout -b my-new-feature`)
51
81
  3. Commit your changes (`git commit -am 'Add some feature'`)
52
82
  4. Push to the branch (`git push origin my-new-feature`)
@@ -4,9 +4,10 @@ module ActiveRecord
4
4
  def attr_encrypted_search(*params)
5
5
  define_attribute_methods rescue nil
6
6
 
7
- options = params.last.is_a?(Hash) ? params.pop.dup : {}
8
- compress = options.delete(:compress) || false
9
- type = options.delete(:type) || :string
7
+ options = params.last.is_a?(Hash) ? params.pop.dup : {}
8
+ compress = options.delete(:compress) || false
9
+ type = options.delete(:type) || :string
10
+ normalize = options.delete(:normalize)
10
11
 
11
12
  raise "Invalid type: #{type.inspect}. Valid types: #{SymmetricEncryption::COERCION_TYPES.inspect}" unless SymmetricEncryption::COERCION_TYPES.include?(type)
12
13
 
@@ -20,14 +21,34 @@ module ActiveRecord
20
21
  end
21
22
 
22
23
  params.each do |attribute|
23
- mod.module_eval(<<-ENCRYPTEDSEARCH, __FILE__, __LINE__ + 1)
24
- def #{attribute}=(value)
24
+ mod.module_eval do
25
+ define_method("#{attribute}=") do |value|
25
26
  if value
26
- self.encrypted_search_#{attribute} = ::SymmetricEncryption.encrypt(value.downcase,false,#{compress},:#{type})
27
+ send(
28
+ "encrypted_search_#{attribute}=",
29
+ ::SymmetricEncryption.encrypt(
30
+ send("normalize_#{attribute}", value),
31
+ false,
32
+ compress,
33
+ type
34
+ )
35
+ )
27
36
  end
28
37
  super(value)
29
38
  end
30
- ENCRYPTEDSEARCH
39
+
40
+ define_method("normalize_#{attribute}") do |value|
41
+ if normalize
42
+ if normalize.respond_to?(:call)
43
+ normalize.call(value)
44
+ else
45
+ send(normalize, value)
46
+ end
47
+ else
48
+ value.downcase
49
+ end
50
+ end
51
+ end
31
52
  end
32
53
 
33
54
  end
@@ -1,3 +1,3 @@
1
1
  module EncryptedSearchAttributes
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -49,6 +49,15 @@ describe 'attr_encrypted_search' do
49
49
  expect(widget.encrypted_search_name).to eq(search_value)
50
50
  end
51
51
 
52
+ it 'correctly handles nil values' do
53
+ widget = Widget.create!(name: nil)
54
+
55
+ expect(widget.encrypted_search_name).to eq(nil)
56
+
57
+ widget.reload
58
+ expect(widget.encrypted_search_name).to eq(nil)
59
+ end
60
+
52
61
  it 'sets encrypted search field on assignment' do
53
62
  widget = Widget.create!
54
63
 
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ db_config_file = File.expand_path('../../config/database.yml', __FILE__)
4
+ encryption_config_file = File.expand_path('../../config/symmetric-encryption.yml', __FILE__)
5
+
6
+ ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(db_config_file)).result)
7
+ ActiveRecord::Base.establish_connection('test')
8
+
9
+ ActiveRecord::Schema.define(version: 0) do
10
+ create_table :widget_with_custom_methods, force: true do |t|
11
+ t.string :encrypted_name
12
+ t.string :encrypted_search_name
13
+ end
14
+ end
15
+
16
+ class WidgetWithCustomMethod < ActiveRecord::Base
17
+ attr_encrypted :name
18
+ attr_encrypted_search :name,
19
+ normalize: :downcase_no_spaces
20
+
21
+ private
22
+
23
+ def downcase_no_spaces(value)
24
+ value.downcase.gsub(' ', '')
25
+ end
26
+ end
27
+
28
+ SymmetricEncryption.load!(encryption_config_file, 'test')
29
+
30
+ # Initialize the database connection
31
+ config = YAML.load(ERB.new(File.new(db_config_file).read).result)['test']
32
+
33
+ WidgetWithCustomMethod.establish_connection(config)
34
+
35
+ describe 'custom method attr_encrypted_search' do
36
+ it 'sets encrypted search field on initialization' do
37
+ widget = WidgetWithCustomMethod.new(name: 'Test Value')
38
+
39
+ search_value = ::SymmetricEncryption.encrypt('testvalue')
40
+ expect(widget.encrypted_search_name).to eq(search_value)
41
+
42
+ widget.save!
43
+ expect(widget.encrypted_search_name).to eq(search_value)
44
+
45
+ widget.reload
46
+ expect(widget.encrypted_search_name).to eq(search_value)
47
+ end
48
+
49
+ it 'sets the encrypted search field on creation' do
50
+ widget = WidgetWithCustomMethod.create!(name: 'Another Test')
51
+
52
+ search_value = ::SymmetricEncryption.encrypt('anothertest')
53
+ expect(widget.encrypted_search_name).to eq(search_value)
54
+
55
+ widget.reload
56
+ expect(widget.encrypted_search_name).to eq(search_value)
57
+ end
58
+
59
+ it 'correctly handles nil values' do
60
+ widget = WidgetWithCustomMethod.create!(name: nil)
61
+
62
+ expect(widget.encrypted_search_name).to eq(nil)
63
+
64
+ widget.reload
65
+ expect(widget.encrypted_search_name).to eq(nil)
66
+ end
67
+
68
+ it 'sets encrypted search field on assignment' do
69
+ widget = WidgetWithCustomMethod.create!
70
+
71
+ widget.name = 'Something Else'
72
+
73
+ search_value = ::SymmetricEncryption.encrypt('somethingelse')
74
+ expect(widget.encrypted_search_name).to eq(search_value)
75
+
76
+ widget.save!
77
+ expect(widget.encrypted_search_name).to eq(search_value)
78
+
79
+ widget.reload
80
+ expect(widget.encrypted_search_name).to eq(search_value)
81
+ end
82
+
83
+ it 'preserves attr_encrypted functionality' do
84
+ widget = WidgetWithCustomMethod.create!(name: 'Anything')
85
+ expect(widget.name).to eq('Anything')
86
+ expect(widget.encrypted_name).to eq(::SymmetricEncryption.encrypt('Anything'))
87
+
88
+ widget.reload
89
+ expect(widget.encrypted_name).to eq(::SymmetricEncryption.encrypt('Anything'))
90
+ end
91
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ db_config_file = File.expand_path('../../config/database.yml', __FILE__)
4
+ encryption_config_file = File.expand_path('../../config/symmetric-encryption.yml', __FILE__)
5
+
6
+ ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(db_config_file)).result)
7
+ ActiveRecord::Base.establish_connection('test')
8
+
9
+ ActiveRecord::Schema.define(version: 0) do
10
+ create_table :widget_with_custom_procs, force: true do |t|
11
+ t.string :encrypted_name
12
+ t.string :encrypted_search_name
13
+ end
14
+ end
15
+
16
+ class WidgetWithCustomProc < ActiveRecord::Base
17
+ attr_encrypted :name
18
+ attr_encrypted_search :name,
19
+ normalize: ->(value) { value.downcase.gsub(' ', '') }
20
+ end
21
+
22
+ SymmetricEncryption.load!(encryption_config_file, 'test')
23
+
24
+ # Initialize the database connection
25
+ config = YAML.load(ERB.new(File.new(db_config_file).read).result)['test']
26
+
27
+ WidgetWithCustomProc.establish_connection(config)
28
+
29
+ describe 'custom proc attr_encrypted_search' do
30
+ it 'sets encrypted search field on initialization' do
31
+ widget = WidgetWithCustomProc.new(name: 'Test Value')
32
+
33
+ search_value = ::SymmetricEncryption.encrypt('testvalue')
34
+ expect(widget.encrypted_search_name).to eq(search_value)
35
+
36
+ widget.save!
37
+ expect(widget.encrypted_search_name).to eq(search_value)
38
+
39
+ widget.reload
40
+ expect(widget.encrypted_search_name).to eq(search_value)
41
+ end
42
+
43
+ it 'sets the encrypted search field on creation' do
44
+ widget = WidgetWithCustomProc.create!(name: 'Another Test')
45
+
46
+ search_value = ::SymmetricEncryption.encrypt('anothertest')
47
+ expect(widget.encrypted_search_name).to eq(search_value)
48
+
49
+ widget.reload
50
+ expect(widget.encrypted_search_name).to eq(search_value)
51
+ end
52
+
53
+ it 'correctly handles nil values' do
54
+ widget = WidgetWithCustomProc.create!(name: nil)
55
+
56
+ expect(widget.encrypted_search_name).to eq(nil)
57
+
58
+ widget.reload
59
+ expect(widget.encrypted_search_name).to eq(nil)
60
+ end
61
+
62
+ it 'sets encrypted search field on assignment' do
63
+ widget = WidgetWithCustomProc.create!
64
+
65
+ widget.name = 'Something Else'
66
+
67
+ search_value = ::SymmetricEncryption.encrypt('somethingelse')
68
+ expect(widget.encrypted_search_name).to eq(search_value)
69
+
70
+ widget.save!
71
+ expect(widget.encrypted_search_name).to eq(search_value)
72
+
73
+ widget.reload
74
+ expect(widget.encrypted_search_name).to eq(search_value)
75
+ end
76
+
77
+ it 'preserves attr_encrypted functionality' do
78
+ widget = WidgetWithCustomProc.create!(name: 'Anything')
79
+ expect(widget.name).to eq('Anything')
80
+ expect(widget.encrypted_name).to eq(::SymmetricEncryption.encrypt('Anything'))
81
+
82
+ widget.reload
83
+ expect(widget.encrypted_name).to eq(::SymmetricEncryption.encrypt('Anything'))
84
+ end
85
+ end
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: encrypted_search_attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - M. Scott Ford
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-06 00:00:00.000000000 Z
11
+ date: 2015-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: symmetric-encryption
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '3.3'
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
26
  version: '3.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 3.2.13
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 3.2.13
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '10.1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '10.1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: 2.14.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 2.14.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: sqlite3
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: 1.3.8
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: 1.3.8
97
97
  description: Encrypting a field makes it very difficult to perform a case insensitive
@@ -104,7 +104,7 @@ executables: []
104
104
  extensions: []
105
105
  extra_rdoc_files: []
106
106
  files:
107
- - .gitignore
107
+ - ".gitignore"
108
108
  - Gemfile
109
109
  - LICENSE.txt
110
110
  - README.md
@@ -114,6 +114,8 @@ files:
114
114
  - lib/encrypted_search_attributes/extensions/active_record/base.rb
115
115
  - lib/encrypted_search_attributes/version.rb
116
116
  - spec/acceptance/attr_encrypted_search_spec.rb
117
+ - spec/acceptance/custom_method_normalizer_spec.rb
118
+ - spec/acceptance/custom_proc_normalizer_spec.rb
117
119
  - spec/config/database.yml
118
120
  - spec/config/symmetric-encryption.yml
119
121
  - spec/config/test_new.iv
@@ -131,22 +133,24 @@ require_paths:
131
133
  - lib
132
134
  required_ruby_version: !ruby/object:Gem::Requirement
133
135
  requirements:
134
- - - ! '>='
136
+ - - ">="
135
137
  - !ruby/object:Gem::Version
136
138
  version: '0'
137
139
  required_rubygems_version: !ruby/object:Gem::Requirement
138
140
  requirements:
139
- - - ! '>='
141
+ - - ">="
140
142
  - !ruby/object:Gem::Version
141
143
  version: '0'
142
144
  requirements: []
143
145
  rubyforge_project:
144
- rubygems_version: 2.1.11
146
+ rubygems_version: 2.4.5
145
147
  signing_key:
146
148
  specification_version: 4
147
149
  summary: Auto populates encrypted fields that are designed for searching
148
150
  test_files:
149
151
  - spec/acceptance/attr_encrypted_search_spec.rb
152
+ - spec/acceptance/custom_method_normalizer_spec.rb
153
+ - spec/acceptance/custom_proc_normalizer_spec.rb
150
154
  - spec/config/database.yml
151
155
  - spec/config/symmetric-encryption.yml
152
156
  - spec/config/test_new.iv