mongoid-encrypted-fields 1.1.0 → 1.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.
- data/.gitignore +3 -1
- data/CHANGLOG.md +4 -0
- data/README.md +6 -0
- data/Rakefile +7 -0
- data/examples/gibberish_cipher.rb +4 -4
- data/lib/mongoid-encrypted-fields.rb +2 -1
- data/lib/mongoid-encrypted-fields/fields/encrypted_field.rb +10 -4
- data/lib/mongoid-encrypted-fields/fields/encrypted_hash.rb +48 -0
- data/lib/mongoid-encrypted-fields/logging.rb +2 -0
- data/lib/mongoid-encrypted-fields/version.rb +1 -1
- data/mongoid-encrypted-fields.gemspec +2 -2
- data/spec/mongoid-encrypted-fields/fields/encrypted_hash_spec.rb +69 -0
- data/spec/mongoid-encrypted-fields/fields/model_spec.rb +19 -1
- data/spec/support/models/person.rb +1 -0
- metadata +20 -17
data/.gitignore
CHANGED
data/CHANGLOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Revision history
|
|
2
2
|
|
|
3
|
+
## 1.2 - Add EncryptedHash
|
|
4
|
+
|
|
5
|
+
* Accepted [pull request](https://github.com/KoanHealth/mongoid-encrypted-fields/pull/4) from ashirazi to add support for encrypted hashes
|
|
6
|
+
|
|
3
7
|
## 1.1 - Breaking changes - PLEASE READ
|
|
4
8
|
|
|
5
9
|
### encrypted-strings gem
|
data/README.md
CHANGED
|
@@ -51,6 +51,12 @@ Queries encrypt data before searching the database, so equality matches work aut
|
|
|
51
51
|
|
|
52
52
|
## Known Limitations
|
|
53
53
|
* Single cipher for all encrypted fields
|
|
54
|
+
* Currently can encrypt these [Mongoid types](http://mongoid.org/en/mongoid/docs/documents.html#fields)
|
|
55
|
+
* Date
|
|
56
|
+
* DateTime
|
|
57
|
+
* Hash
|
|
58
|
+
* String
|
|
59
|
+
* Time
|
|
54
60
|
|
|
55
61
|
## Copyright
|
|
56
62
|
(c) 2012 Koan Health. See LICENSE.txt for further details.
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'gibberish/aes'
|
|
2
2
|
|
|
3
|
-
# Gibberish uses a unique salt for every encryption, but we need the same text
|
|
4
|
-
# so Searching for encrypted field will work
|
|
3
|
+
# Gibberish uses a unique salt for every encryption, but we need the same text
|
|
4
|
+
# to return the same ciphertext so Searching for encrypted field will work
|
|
5
5
|
class GibberishCipher < Gibberish::AES
|
|
6
6
|
|
|
7
7
|
SALT = "OU812FTW" # TODO: If you use this example class, make a unique 8-byte salt for your project
|
|
@@ -11,9 +11,9 @@ class GibberishCipher < Gibberish::AES
|
|
|
11
11
|
@salt = options[:salt] || SALT
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def generate_salt
|
|
14
|
+
def generate_salt(supplied_salt)
|
|
15
15
|
return @salt if @salt
|
|
16
16
|
super
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
end
|
|
19
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'mongoid-encrypted-fields/version'
|
|
2
2
|
require 'mongoid-encrypted-fields/logging'
|
|
3
3
|
require 'mongoid-encrypted-fields/fields/encrypted_field'
|
|
4
|
+
require 'mongoid-encrypted-fields/fields/encrypted_hash'
|
|
4
5
|
require 'mongoid-encrypted-fields/fields/encrypted_string'
|
|
5
6
|
require 'mongoid-encrypted-fields/fields/encrypted_date'
|
|
6
7
|
require 'mongoid-encrypted-fields/fields/encrypted_date_time'
|
|
@@ -15,4 +16,4 @@ module Mongoid
|
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
end
|
|
18
|
-
end
|
|
19
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
require
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
require 'base64'
|
|
2
3
|
|
|
3
4
|
module Mongoid
|
|
4
5
|
module EncryptedField
|
|
@@ -6,10 +7,10 @@ module Mongoid
|
|
|
6
7
|
|
|
7
8
|
def encrypted
|
|
8
9
|
if frozen?
|
|
9
|
-
@encrypted ||= self.class.encrypt(
|
|
10
|
+
@encrypted ||= self.class.encrypt(raw_value)
|
|
10
11
|
else
|
|
11
12
|
# We are mutable - need to encrypt whenever asked
|
|
12
|
-
self.class.encrypt(
|
|
13
|
+
self.class.encrypt(raw_value)
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
|
|
@@ -18,6 +19,11 @@ module Mongoid
|
|
|
18
19
|
encrypted
|
|
19
20
|
end
|
|
20
21
|
|
|
22
|
+
# Provide string to be encrypted and stored in Mongo DB
|
|
23
|
+
def raw_value
|
|
24
|
+
to_s
|
|
25
|
+
end
|
|
26
|
+
|
|
21
27
|
module ClassMethods
|
|
22
28
|
|
|
23
29
|
# Get the object as it was stored in the database, and instantiate this custom class from it.
|
|
@@ -72,4 +78,4 @@ module Mongoid
|
|
|
72
78
|
end
|
|
73
79
|
|
|
74
80
|
end
|
|
75
|
-
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Used to store an encrypted hash in Mongo
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# field :address, type: Mongoid::EncryptedHash
|
|
7
|
+
#
|
|
8
|
+
# Set with an unencrypted hash
|
|
9
|
+
# p = Person.new()
|
|
10
|
+
# p.address = {street: "123 Main St", city: "Springdale", state: "MD"}
|
|
11
|
+
#
|
|
12
|
+
# Get returns the unencrypted hash
|
|
13
|
+
# puts p.address -> {:street=>"123 Main St", :city=>"Springdale", :state=>"MD"}
|
|
14
|
+
#
|
|
15
|
+
# Use the encrypted property to see the encrypted value
|
|
16
|
+
# puts p.address.encrypted -> '....'
|
|
17
|
+
require 'yaml'
|
|
18
|
+
|
|
19
|
+
module Mongoid
|
|
20
|
+
class EncryptedHash < ::Hash
|
|
21
|
+
include Mongoid::EncryptedField
|
|
22
|
+
|
|
23
|
+
# Return value to be encrypted
|
|
24
|
+
def raw_value
|
|
25
|
+
to_yaml
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
|
|
30
|
+
# converts from a plain Hash to an EncryptedHash
|
|
31
|
+
def from_hash(h)
|
|
32
|
+
self[h.to_hash]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Takes an object representation (Hash or string) and converts it to an
|
|
36
|
+
# EncryptedHash.
|
|
37
|
+
def convert(object)
|
|
38
|
+
case object
|
|
39
|
+
when Hash
|
|
40
|
+
from_hash(object)
|
|
41
|
+
else
|
|
42
|
+
from_hash(::YAML.load(object))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -17,10 +17,10 @@ Gem::Specification.new do |gem|
|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
18
18
|
gem.require_paths = ["lib"]
|
|
19
19
|
|
|
20
|
-
gem.add_dependency "rake"
|
|
21
20
|
gem.add_dependency "mongoid", "~> 3"
|
|
22
21
|
|
|
22
|
+
gem.add_development_dependency "rake"
|
|
23
23
|
gem.add_development_dependency "rspec"
|
|
24
|
-
gem.add_development_dependency "gibberish", "~> 1.2"
|
|
24
|
+
gem.add_development_dependency "gibberish", "~> 1.2.2"
|
|
25
25
|
gem.add_development_dependency "encrypted_strings", "~> 0.3"
|
|
26
26
|
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
describe EncryptedHash do
|
|
5
|
+
|
|
6
|
+
before(:all) do
|
|
7
|
+
Mongoid::EncryptedFields.cipher = GibberishCipher.new('my test password')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
subject { Mongoid::EncryptedHash }
|
|
11
|
+
let(:raw) { {street: "123 Main St", city: "Springdale", state: "MD"} }
|
|
12
|
+
let(:encrypted) { Mongoid::EncryptedHash.mongoize({street: "123 Main St", city: "Springdale", state: "MD"}) }
|
|
13
|
+
|
|
14
|
+
it "returns the same hash" do
|
|
15
|
+
subject.from_hash(raw).should eq(raw)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should encrypt the hash" do
|
|
19
|
+
subject.from_hash(raw).encrypted.should eq(encrypted)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "nil should fail" do
|
|
23
|
+
-> { subject.from_hash(nil) }.should raise_error()
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "demongoize" do
|
|
27
|
+
|
|
28
|
+
it "nil should return nil" do
|
|
29
|
+
subject.demongoize(nil).should be_nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "blank string should return blank string" do
|
|
33
|
+
subject.demongoize('').should eq('')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "invalid hash should fail" do
|
|
37
|
+
-> { subject.demongoize('not a hash') }.should raise_error
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "encrypted hash should return unencrypted hash" do
|
|
41
|
+
decrypted = subject.demongoize(encrypted)
|
|
42
|
+
decrypted.is_a?(subject).should be_true
|
|
43
|
+
decrypted.should eq(raw)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "mongoize" do
|
|
49
|
+
|
|
50
|
+
it "encrypted hash should return encrypted" do
|
|
51
|
+
subject.mongoize(subject.from_hash(raw)).should eq(encrypted)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "encrypted hash should return itself" do
|
|
55
|
+
subject.mongoize(encrypted).should eq(encrypted)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "nil should return nil" do
|
|
59
|
+
subject.mongoize(nil).should eq(nil)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "valid hash should return encrypted" do
|
|
63
|
+
subject.mongoize(raw).should eq(encrypted)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -10,7 +10,9 @@ describe 'Single model' do
|
|
|
10
10
|
let (:ssn_encrypted) { Mongoid::EncryptedString.mongoize(ssn) }
|
|
11
11
|
let (:birth_date) { 20.years.ago.to_date }
|
|
12
12
|
let (:birth_date_encrypted) { Mongoid::EncryptedDate.mongoize(birth_date) }
|
|
13
|
-
let (:
|
|
13
|
+
let (:address) { {street: '123 Main St', city: 'Anytown', state: 'TX' } }
|
|
14
|
+
let (:address_encrypted) { Mongoid::EncryptedHash.mongoize(address) }
|
|
15
|
+
let (:person) { Person.new(name: 'John Doe', ssn: ssn, birth_date: birth_date, address: address) }
|
|
14
16
|
|
|
15
17
|
it "model stores encrypted ssn" do
|
|
16
18
|
person.attributes['ssn'].should eq(ssn_encrypted)
|
|
@@ -20,6 +22,10 @@ describe 'Single model' do
|
|
|
20
22
|
person.attributes['birth_date'].should eq(birth_date_encrypted)
|
|
21
23
|
end
|
|
22
24
|
|
|
25
|
+
it "model stores encrypted address" do
|
|
26
|
+
person.attributes['address'].should eq(address_encrypted)
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
it "ssn getter returns raw value" do
|
|
24
30
|
person.ssn.should eq(ssn)
|
|
25
31
|
end
|
|
@@ -28,6 +34,10 @@ describe 'Single model' do
|
|
|
28
34
|
person.birth_date.should eq(birth_date)
|
|
29
35
|
end
|
|
30
36
|
|
|
37
|
+
it "address getter returns raw value" do
|
|
38
|
+
person.address.should eq(address)
|
|
39
|
+
end
|
|
40
|
+
|
|
31
41
|
describe "after save" do
|
|
32
42
|
|
|
33
43
|
before(:each) do
|
|
@@ -44,6 +54,10 @@ describe 'Single model' do
|
|
|
44
54
|
@persisted.attributes['birth_date'].should eq(birth_date_encrypted)
|
|
45
55
|
end
|
|
46
56
|
|
|
57
|
+
it "encrypted address is persisted" do
|
|
58
|
+
@persisted.attributes['address'].should eq(address_encrypted)
|
|
59
|
+
end
|
|
60
|
+
|
|
47
61
|
it "encrypted ssn getter returns raw value" do
|
|
48
62
|
@persisted.ssn.should eq(ssn)
|
|
49
63
|
end
|
|
@@ -52,6 +66,10 @@ describe 'Single model' do
|
|
|
52
66
|
@persisted.birth_date.should eq(birth_date)
|
|
53
67
|
end
|
|
54
68
|
|
|
69
|
+
it "encrypted address getter returns raw value" do
|
|
70
|
+
@persisted.address.should eq(address)
|
|
71
|
+
end
|
|
72
|
+
|
|
55
73
|
end
|
|
56
74
|
|
|
57
75
|
describe "find model by encrypted field" do
|
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.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,40 +9,40 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-
|
|
12
|
+
date: 2013-03-20 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
|
-
name:
|
|
15
|
+
name: mongoid
|
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
|
-
- -
|
|
19
|
+
- - ~>
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: '
|
|
21
|
+
version: '3'
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
25
|
none: false
|
|
26
26
|
requirements:
|
|
27
|
-
- -
|
|
27
|
+
- - ~>
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: '
|
|
29
|
+
version: '3'
|
|
30
30
|
- !ruby/object:Gem::Dependency
|
|
31
|
-
name:
|
|
31
|
+
name: rake
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
|
33
33
|
none: false
|
|
34
34
|
requirements:
|
|
35
|
-
- -
|
|
35
|
+
- - ! '>='
|
|
36
36
|
- !ruby/object:Gem::Version
|
|
37
|
-
version: '
|
|
38
|
-
type: :
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
39
|
prerelease: false
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
|
41
41
|
none: false
|
|
42
42
|
requirements:
|
|
43
|
-
- -
|
|
43
|
+
- - ! '>='
|
|
44
44
|
- !ruby/object:Gem::Version
|
|
45
|
-
version: '
|
|
45
|
+
version: '0'
|
|
46
46
|
- !ruby/object:Gem::Dependency
|
|
47
47
|
name: rspec
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -66,7 +66,7 @@ dependencies:
|
|
|
66
66
|
requirements:
|
|
67
67
|
- - ~>
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
|
-
version:
|
|
69
|
+
version: 1.2.2
|
|
70
70
|
type: :development
|
|
71
71
|
prerelease: false
|
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -74,7 +74,7 @@ dependencies:
|
|
|
74
74
|
requirements:
|
|
75
75
|
- - ~>
|
|
76
76
|
- !ruby/object:Gem::Version
|
|
77
|
-
version:
|
|
77
|
+
version: 1.2.2
|
|
78
78
|
- !ruby/object:Gem::Dependency
|
|
79
79
|
name: encrypted_strings
|
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -113,6 +113,7 @@ files:
|
|
|
113
113
|
- lib/mongoid-encrypted-fields/fields/encrypted_date.rb
|
|
114
114
|
- lib/mongoid-encrypted-fields/fields/encrypted_date_time.rb
|
|
115
115
|
- lib/mongoid-encrypted-fields/fields/encrypted_field.rb
|
|
116
|
+
- lib/mongoid-encrypted-fields/fields/encrypted_hash.rb
|
|
116
117
|
- lib/mongoid-encrypted-fields/fields/encrypted_string.rb
|
|
117
118
|
- lib/mongoid-encrypted-fields/fields/encrypted_time.rb
|
|
118
119
|
- lib/mongoid-encrypted-fields/logging.rb
|
|
@@ -122,6 +123,7 @@ files:
|
|
|
122
123
|
- spec/mongoid-encrypted-fields/fields/encrypted_date_spec.rb
|
|
123
124
|
- spec/mongoid-encrypted-fields/fields/encrypted_datetime_spec.rb
|
|
124
125
|
- spec/mongoid-encrypted-fields/fields/encrypted_field_spec.rb
|
|
126
|
+
- spec/mongoid-encrypted-fields/fields/encrypted_hash_spec.rb
|
|
125
127
|
- spec/mongoid-encrypted-fields/fields/encrypted_string_spec.rb
|
|
126
128
|
- spec/mongoid-encrypted-fields/fields/encrypted_time_spec.rb
|
|
127
129
|
- spec/mongoid-encrypted-fields/fields/model_spec.rb
|
|
@@ -141,7 +143,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
141
143
|
version: '0'
|
|
142
144
|
segments:
|
|
143
145
|
- 0
|
|
144
|
-
hash: -
|
|
146
|
+
hash: -3259061833501052041
|
|
145
147
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
148
|
none: false
|
|
147
149
|
requirements:
|
|
@@ -150,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
150
152
|
version: '0'
|
|
151
153
|
segments:
|
|
152
154
|
- 0
|
|
153
|
-
hash: -
|
|
155
|
+
hash: -3259061833501052041
|
|
154
156
|
requirements: []
|
|
155
157
|
rubyforge_project:
|
|
156
158
|
rubygems_version: 1.8.25
|
|
@@ -162,6 +164,7 @@ test_files:
|
|
|
162
164
|
- spec/mongoid-encrypted-fields/fields/encrypted_date_spec.rb
|
|
163
165
|
- spec/mongoid-encrypted-fields/fields/encrypted_datetime_spec.rb
|
|
164
166
|
- spec/mongoid-encrypted-fields/fields/encrypted_field_spec.rb
|
|
167
|
+
- spec/mongoid-encrypted-fields/fields/encrypted_hash_spec.rb
|
|
165
168
|
- spec/mongoid-encrypted-fields/fields/encrypted_string_spec.rb
|
|
166
169
|
- spec/mongoid-encrypted-fields/fields/encrypted_time_spec.rb
|
|
167
170
|
- spec/mongoid-encrypted-fields/fields/model_spec.rb
|