mongoid-encrypted-fields 1.2.0 → 1.2.1
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.
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGLOG.md +2 -0
- data/README.md +14 -1
- data/examples/gibberish_cipher.rb +11 -10
- data/lib/mongoid-encrypted-fields.rb +1 -0
- data/lib/mongoid-encrypted-fields/validations/uniqueness.rb +30 -0
- data/lib/mongoid-encrypted-fields/version.rb +1 -1
- data/spec/mongoid-encrypted-fields/fields/encrypted_date_spec.rb +1 -1
- data/spec/mongoid-encrypted-fields/fields/encrypted_datetime_spec.rb +1 -1
- data/spec/mongoid-encrypted-fields/fields/encrypted_field_spec.rb +1 -1
- data/spec/mongoid-encrypted-fields/fields/encrypted_hash_spec.rb +1 -1
- data/spec/mongoid-encrypted-fields/fields/encrypted_string_spec.rb +1 -1
- data/spec/mongoid-encrypted-fields/fields/encrypted_time_spec.rb +1 -1
- data/spec/mongoid-encrypted-fields/fields/model_spec.rb +1 -1
- data/spec/mongoid-encrypted-fields/validations/uniqueness_spec.rb +99 -0
- metadata +9 -4
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mongoid-encrypted-fields
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3
|
data/CHANGLOG.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Revision history
|
2
2
|
|
3
|
+
## 1.2.1 - Uniqueness validator fails if developer attempts to use case-insensitive option for an encrypted field
|
4
|
+
|
3
5
|
## 1.2 - Add EncryptedHash
|
4
6
|
|
5
7
|
* Accepted [pull request](https://github.com/KoanHealth/mongoid-encrypted-fields/pull/4) from ashirazi to add support for encrypted hashes
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ Queries encrypt data before searching the database, so equality matches work aut
|
|
20
20
|
|
21
21
|
GibberishCipher can be found in examples - uses the [Gibberish](https://github.com/mdp/gibberish) gem:
|
22
22
|
```Ruby
|
23
|
-
Mongoid::EncryptedFields.cipher = GibberishCipher.new(ENV['MY_PASSWORD'])
|
23
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new(ENV['MY_PASSWORD'], ENV['MY_SALT'])
|
24
24
|
```
|
25
25
|
|
26
26
|
* Use encrypted types for fields in your models:
|
@@ -48,6 +48,18 @@ Queries encrypt data before searching the database, so equality matches work aut
|
|
48
48
|
```Ruby
|
49
49
|
Person.where(ssn: '123456789').count() # ssn is encrypted before querying the database
|
50
50
|
```
|
51
|
+
* The Mongoid uniqueness validator is patched to detect of encrypted fields:
|
52
|
+
```Ruby
|
53
|
+
class Person
|
54
|
+
...
|
55
|
+
field :ssn, type: Mongoid::EncryptedString
|
56
|
+
validates_uniqueness_of :ssn, case_sensitive: true # Works as expected
|
57
|
+
validates_uniqueness_of :ssn, case_sensitive: false # Raises exception - encrypted field cannot support a case insensitive match
|
58
|
+
end
|
59
|
+
|
60
|
+
Person.create!(name: 'Bill', ssn: '123456789')
|
61
|
+
Person.create!(name: 'Ted', ssn: '123456789') #=> fails with uniqueness error
|
62
|
+
```
|
51
63
|
|
52
64
|
## Known Limitations
|
53
65
|
* Single cipher for all encrypted fields
|
@@ -57,6 +69,7 @@ Queries encrypt data before searching the database, so equality matches work aut
|
|
57
69
|
* Hash
|
58
70
|
* String
|
59
71
|
* Time
|
72
|
+
* The uniqueness validator for encrypted fields is always case-sensitive. Using it with case-sensitive false raises an exception.
|
60
73
|
|
61
74
|
## Copyright
|
62
75
|
(c) 2012 Koan Health. See LICENSE.txt for further details.
|
@@ -1,19 +1,20 @@
|
|
1
1
|
require 'gibberish/aes'
|
2
2
|
|
3
|
-
# Gibberish uses a unique salt for every encryption, but we need the same text
|
4
|
-
#
|
5
|
-
class GibberishCipher
|
3
|
+
# Gibberish uses a unique salt for every encryption, but we need the same text to return the same ciphertext
|
4
|
+
# so Searching for encrypted field will work
|
5
|
+
class GibberishCipher
|
6
6
|
|
7
|
-
|
7
|
+
def initialize(password, salt)
|
8
|
+
@cipher = Gibberish::AES.new(password)
|
9
|
+
@salt = salt
|
10
|
+
end
|
8
11
|
|
9
|
-
def
|
10
|
-
|
11
|
-
@salt = options[:salt] || SALT
|
12
|
+
def encrypt(data)
|
13
|
+
@cipher.encrypt(data, salt: @salt)
|
12
14
|
end
|
13
15
|
|
14
|
-
def
|
15
|
-
|
16
|
-
super
|
16
|
+
def decrypt(data)
|
17
|
+
@cipher.decrypt(data)
|
17
18
|
end
|
18
19
|
|
19
20
|
end
|
@@ -6,6 +6,7 @@ require 'mongoid-encrypted-fields/fields/encrypted_string'
|
|
6
6
|
require 'mongoid-encrypted-fields/fields/encrypted_date'
|
7
7
|
require 'mongoid-encrypted-fields/fields/encrypted_date_time'
|
8
8
|
require 'mongoid-encrypted-fields/fields/encrypted_time'
|
9
|
+
require 'mongoid-encrypted-fields/validations/uniqueness'
|
9
10
|
|
10
11
|
module Mongoid
|
11
12
|
module EncryptedFields
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mongoid
|
4
|
+
module Validations # renamed to module Validatable in Mongoid 4.0
|
5
|
+
|
6
|
+
# Monkey-patch for Mongoid's uniqueness validator to encrypt
|
7
|
+
# uniqueness test values before querying the database
|
8
|
+
#
|
9
|
+
# Patch is confirmed to work on Mongoid >= 3.0.0
|
10
|
+
# Should work in Mongoid >= 4.0.0 by renaming module Validations to Validatable
|
11
|
+
#
|
12
|
+
# A known limitation is that the :case_sensitive option does not work
|
13
|
+
# for encrypted fields; they must always be case-sensitive.
|
14
|
+
class UniquenessValidator
|
15
|
+
|
16
|
+
def setup_with_validation(klass)
|
17
|
+
setup_without_validation(klass)
|
18
|
+
return if case_sensitive?
|
19
|
+
attributes.each do |attribute|
|
20
|
+
field_type = @klass.fields[attribute.to_s].options[:type]
|
21
|
+
raise ArgumentError, "Encrypted field :#{attribute} cannot support case insensitive uniqueness" if field_type.method_defined?(:encrypted)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
alias_method :setup_without_validation, :setup
|
26
|
+
alias_method :setup, :setup_with_validation
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -4,7 +4,7 @@ module Mongoid
|
|
4
4
|
describe EncryptedDate do
|
5
5
|
|
6
6
|
before(:all) do
|
7
|
-
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password')
|
7
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password', 'weaksalt')
|
8
8
|
end
|
9
9
|
|
10
10
|
subject { Mongoid::EncryptedDate }
|
@@ -4,7 +4,7 @@ module Mongoid
|
|
4
4
|
describe EncryptedDateTime do
|
5
5
|
|
6
6
|
before(:all) do
|
7
|
-
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password')
|
7
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password', 'weaksalt')
|
8
8
|
end
|
9
9
|
|
10
10
|
subject { Mongoid::EncryptedDateTime }
|
@@ -4,7 +4,7 @@ module Mongoid
|
|
4
4
|
describe EncryptedField do
|
5
5
|
|
6
6
|
before(:all) do
|
7
|
-
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password')
|
7
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password', 'weaksalt')
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should encrypt and decrypt a string" do
|
@@ -4,7 +4,7 @@ module Mongoid
|
|
4
4
|
describe EncryptedHash do
|
5
5
|
|
6
6
|
before(:all) do
|
7
|
-
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password')
|
7
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password', 'weaksalt')
|
8
8
|
end
|
9
9
|
|
10
10
|
subject { Mongoid::EncryptedHash }
|
@@ -4,7 +4,7 @@ module Mongoid
|
|
4
4
|
describe EncryptedTime do
|
5
5
|
|
6
6
|
before(:all) do
|
7
|
-
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password')
|
7
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password', 'weaksalt')
|
8
8
|
end
|
9
9
|
|
10
10
|
subject { Mongoid::EncryptedTime }
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe 'Single model' do
|
4
4
|
|
5
5
|
before(:all) do
|
6
|
-
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password')
|
6
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password', 'weaksalt')
|
7
7
|
end
|
8
8
|
|
9
9
|
let (:ssn) { '123456789' }
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Validations::UniquenessValidator do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password', 'weaksalt')
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
Mongoid.purge!
|
11
|
+
Mongoid::IdentityMap.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#valid?" do
|
15
|
+
|
16
|
+
let(:person) do
|
17
|
+
Person.new(name: "bill", ssn: "abc456789")
|
18
|
+
end
|
19
|
+
|
20
|
+
after do
|
21
|
+
Person.reset_callbacks(:validate)
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when the value is in conflict" do
|
25
|
+
|
26
|
+
context "when the field is not encrypted" do
|
27
|
+
|
28
|
+
context "when the validation is case-sensitive" do
|
29
|
+
|
30
|
+
before do
|
31
|
+
Person.validates_uniqueness_of :name, case_sensitive: true
|
32
|
+
Person.create!(name: "bill")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "correctly detects a uniqueness conflict" do
|
36
|
+
expect(person).to_not be_valid
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when the validation is case-insensitive" do
|
41
|
+
|
42
|
+
before do
|
43
|
+
Person.validates_uniqueness_of :name, case_sensitive: false
|
44
|
+
Person.create!(name: "BiLl")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "behaves as case-insensitive" do
|
48
|
+
expect(person).to_not be_valid
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the field is encrypted" do
|
54
|
+
|
55
|
+
context "when the validation is case-sensitive" do
|
56
|
+
|
57
|
+
it "behaves as case-sensitive" do
|
58
|
+
expect(person).to be_valid
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "when the validation is case-insensitive" do
|
63
|
+
|
64
|
+
it "throws an exception" do
|
65
|
+
expect { Person.validates_uniqueness_of :ssn, case_sensitive: false }.to raise_error 'Encrypted field :ssn cannot support case insensitive uniqueness'
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when the value is not conflict" do
|
73
|
+
|
74
|
+
context "when the field is not encrypted" do
|
75
|
+
|
76
|
+
before do
|
77
|
+
Person.validates_uniqueness_of :name
|
78
|
+
Person.create!(name: "ted")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "correctly detects a uniqueness conflict" do
|
82
|
+
expect(person).to be_valid
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when the field is encrypted" do
|
87
|
+
|
88
|
+
before do
|
89
|
+
Person.validates_uniqueness_of :ssn
|
90
|
+
Person.create!(ssn: "223456789")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "correctly detects a uniqueness conflict" do
|
94
|
+
expect(person).to be_valid
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-encrypted-fields
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mongoid
|
@@ -100,6 +100,8 @@ extra_rdoc_files: []
|
|
100
100
|
files:
|
101
101
|
- .gitignore
|
102
102
|
- .rspec
|
103
|
+
- .ruby-gemset
|
104
|
+
- .ruby-version
|
103
105
|
- .rvmrc
|
104
106
|
- CHANGLOG.md
|
105
107
|
- Gemfile
|
@@ -117,6 +119,7 @@ files:
|
|
117
119
|
- lib/mongoid-encrypted-fields/fields/encrypted_string.rb
|
118
120
|
- lib/mongoid-encrypted-fields/fields/encrypted_time.rb
|
119
121
|
- lib/mongoid-encrypted-fields/logging.rb
|
122
|
+
- lib/mongoid-encrypted-fields/validations/uniqueness.rb
|
120
123
|
- lib/mongoid-encrypted-fields/version.rb
|
121
124
|
- mongoid-encrypted-fields.gemspec
|
122
125
|
- spec/config/mongoid.yml
|
@@ -127,6 +130,7 @@ files:
|
|
127
130
|
- spec/mongoid-encrypted-fields/fields/encrypted_string_spec.rb
|
128
131
|
- spec/mongoid-encrypted-fields/fields/encrypted_time_spec.rb
|
129
132
|
- spec/mongoid-encrypted-fields/fields/model_spec.rb
|
133
|
+
- spec/mongoid-encrypted-fields/validations/uniqueness_spec.rb
|
130
134
|
- spec/spec_helper.rb
|
131
135
|
- spec/support/models/person.rb
|
132
136
|
homepage: https://github.com/KoanHealth/mongoid-encrypted-fields
|
@@ -143,7 +147,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
143
147
|
version: '0'
|
144
148
|
segments:
|
145
149
|
- 0
|
146
|
-
hash:
|
150
|
+
hash: 3728144320335115622
|
147
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
152
|
none: false
|
149
153
|
requirements:
|
@@ -152,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
156
|
version: '0'
|
153
157
|
segments:
|
154
158
|
- 0
|
155
|
-
hash:
|
159
|
+
hash: 3728144320335115622
|
156
160
|
requirements: []
|
157
161
|
rubyforge_project:
|
158
162
|
rubygems_version: 1.8.25
|
@@ -168,5 +172,6 @@ test_files:
|
|
168
172
|
- spec/mongoid-encrypted-fields/fields/encrypted_string_spec.rb
|
169
173
|
- spec/mongoid-encrypted-fields/fields/encrypted_time_spec.rb
|
170
174
|
- spec/mongoid-encrypted-fields/fields/model_spec.rb
|
175
|
+
- spec/mongoid-encrypted-fields/validations/uniqueness_spec.rb
|
171
176
|
- spec/spec_helper.rb
|
172
177
|
- spec/support/models/person.rb
|