encrypted_search_attributes 1.0.1 → 1.1.0

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