mongoid-encrypted-fields 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|