symmetric-encryption 2.0.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac5f1b64a033b9aa7bd5b9dc2966318dab30609c
4
- data.tar.gz: a5a010ede4476c92caab94fc5f7f697b8bd38395
3
+ metadata.gz: 21f271484936806efc343704e1bfac1392239fa0
4
+ data.tar.gz: 53aff815835c31c9677eae87db94336cc72db0e5
5
5
  SHA512:
6
- metadata.gz: 2d003387010b20ee1f61d59165982d54a26cc70d1bb95859215a156b3be65b5c1c2ccb59b43add0b85424b2a1f21a99a76e62405cf9375e2542880e56b9e8d58
7
- data.tar.gz: 8b18f43416c1e8c6c5d30cba207727bc2ae29e17eb48cc264f53fbe1a37dee37e5b4fbe9cccd73f9a5ae6ec5482045f58c8415f0a37d247a81b63f6d4f5eaa37
6
+ metadata.gz: 89aab4b1b54a70e9e24023c074e03950b298376e6b97bc13a9a2597c5c6eaf1184ec7405ae6fe2ee898d31df7114589977a2d5e0cb2856ecd25641c186780f35
7
+ data.tar.gz: 08e333431de1b029ced0888c182efe67ad09d1e33e5164cb99a9c9103b990e3f532daa95358ad1bb257faf7fbd41e881a6cb2644631b749271500e71d7b01faa
data/Gemfile CHANGED
@@ -1,11 +1,10 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  group :test do
4
- gem "shoulda"
4
+ gem 'rake'
5
+ gem 'shoulda'
5
6
 
6
- # Limited to Rails 3.2.x only because of Mongoid dependency below
7
- # If Mongoid Appender is not used, Rails 4 should work fine
8
- gem "activerecord", "~> 3.2.0"
7
+ gem 'activerecord'
9
8
  gem 'sqlite3', :platform => :ruby
10
9
 
11
10
  platforms :jruby do
@@ -13,5 +12,8 @@ group :test do
13
12
  gem 'activerecord-jdbcsqlite3-adapter'
14
13
  end
15
14
 
16
- gem "mongoid", "~> 3.1.0"
15
+ # Use Mongo as the database with Mongoid as the Object Document Mapper
16
+ # Edge has support for Rails 4
17
+ gem 'mongoid', git: 'https://github.com/mongoid/mongoid.git'
18
+ gem 'awesome_print'
17
19
  end
@@ -1,28 +1,41 @@
1
- GEM
2
- remote: http://rubygems.org/
1
+ GIT
2
+ remote: https://github.com/mongoid/mongoid.git
3
+ revision: cb541fa1fd7cf9ab0a725c757490d0ac435a79f7
3
4
  specs:
4
- activemodel (3.2.13)
5
- activesupport (= 3.2.13)
6
- builder (~> 3.0.0)
7
- activerecord (3.2.13)
8
- activemodel (= 3.2.13)
9
- activesupport (= 3.2.13)
10
- arel (~> 3.0.2)
11
- tzinfo (~> 0.3.29)
12
- activesupport (3.2.13)
13
- i18n (= 0.6.1)
14
- multi_json (~> 1.0)
15
- arel (3.0.2)
16
- builder (3.0.4)
17
- i18n (0.6.1)
18
- mongoid (3.1.4)
19
- activemodel (~> 3.2)
20
- moped (~> 1.4)
5
+ mongoid (4.0.0)
6
+ activemodel (~> 4.0.0)
7
+ moped (~> 1.5)
21
8
  origin (~> 1.0)
22
9
  tzinfo (~> 0.3.22)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ activemodel (4.0.0)
15
+ activesupport (= 4.0.0)
16
+ builder (~> 3.1.0)
17
+ activerecord (4.0.0)
18
+ activemodel (= 4.0.0)
19
+ activerecord-deprecated_finders (~> 1.0.2)
20
+ activesupport (= 4.0.0)
21
+ arel (~> 4.0.0)
22
+ activerecord-deprecated_finders (1.0.3)
23
+ activesupport (4.0.0)
24
+ i18n (~> 0.6, >= 0.6.4)
25
+ minitest (~> 4.2)
26
+ multi_json (~> 1.3)
27
+ thread_safe (~> 0.1)
28
+ tzinfo (~> 0.3.37)
29
+ arel (4.0.0)
30
+ atomic (1.1.10)
31
+ awesome_print (1.1.0)
32
+ builder (3.1.4)
33
+ i18n (0.6.4)
34
+ minitest (4.7.5)
23
35
  moped (1.5.0)
24
36
  multi_json (1.7.7)
25
37
  origin (1.1.0)
38
+ rake (10.1.0)
26
39
  shoulda (3.5.0)
27
40
  shoulda-context (~> 1.0, >= 1.0.1)
28
41
  shoulda-matchers (>= 1.4.1, < 3.0)
@@ -30,15 +43,19 @@ GEM
30
43
  shoulda-matchers (2.2.0)
31
44
  activesupport (>= 3.0.0)
32
45
  sqlite3 (1.3.7)
46
+ thread_safe (0.1.0)
47
+ atomic
33
48
  tzinfo (0.3.37)
34
49
 
35
50
  PLATFORMS
36
51
  ruby
37
52
 
38
53
  DEPENDENCIES
39
- activerecord (~> 3.2.0)
54
+ activerecord
40
55
  activerecord-jdbcsqlite3-adapter
56
+ awesome_print
41
57
  jdbc-sqlite3
42
- mongoid (~> 3.1.0)
58
+ mongoid!
59
+ rake
43
60
  shoulda
44
61
  sqlite3
data/README.md CHANGED
@@ -79,7 +79,7 @@ option will result in different encrypted output every time it is encrypted.
79
79
  * Encryption of passwords in configuration files
80
80
  * Encryption of ActiveRecord model attributes by prefixing attributes / column
81
81
  names with encrypted_
82
- * Encryption of Mongoid model fields by adding :encrypted => true to field
82
+ * Encryption of Mongoid model fields by adding :encrypted option to field
83
83
  definitions
84
84
  * Externalization of symmetric encryption keys so that they are not in the
85
85
  source code, or the source code control system
@@ -160,7 +160,7 @@ class User
160
160
  field :name, :type => String
161
161
  field :encrypted_bank_account_number, :type => String, :encrypted => true
162
162
  field :encrypted_social_security_number, :type => String, :encrypted => true
163
- field :encrypted_life_history, :type => String, :encrypted => true, :compress => true, :random_iv => true
163
+ field :encrypted_life_history, :type => String, :encrypted => {:compress => true, :random_iv => true}
164
164
  end
165
165
 
166
166
  # Create a new user document
@@ -18,5 +18,5 @@ end
18
18
 
19
19
  # field encryption for Mongoid
20
20
  if defined?(Mongoid)
21
- require 'symmetric_encryption/extensions/mongoid/fields'
21
+ require 'symmetric_encryption/mongoid'
22
22
  end
@@ -54,7 +54,7 @@ module ActiveRecord #:nodoc:
54
54
  # If this method is not called, then the encrypted value is never decrypted
55
55
  def #{attribute}
56
56
  if @stored_encrypted_#{attribute} != self.encrypted_#{attribute}
57
- @#{attribute} = ::SymmetricEncryption.decrypt(self.encrypted_#{attribute})
57
+ @#{attribute} = ::SymmetricEncryption.decrypt(self.encrypted_#{attribute}).freeze
58
58
  @stored_encrypted_#{attribute} = self.encrypted_#{attribute}
59
59
  end
60
60
  @#{attribute}
@@ -64,7 +64,7 @@ module ActiveRecord #:nodoc:
64
64
  # Also updates the encrypted field with the encrypted value
65
65
  def #{attribute}=(value)
66
66
  self.encrypted_#{attribute} = @stored_encrypted_#{attribute} = ::SymmetricEncryption.encrypt(value#{".to_yaml" if marshal},#{random_iv},#{compress})
67
- @#{attribute} = value
67
+ @#{attribute} = value.freeze
68
68
  end
69
69
  UNENCRYPTED
70
70
 
@@ -0,0 +1,118 @@
1
+ # Add :encrypted option for Mongoid models
2
+ #
3
+ # Example:
4
+ #
5
+ # require 'mongoid'
6
+ # require 'symmetric-encryption'
7
+ #
8
+ # # Initialize Mongoid in a standalone environment. In a Rails app this is not required
9
+ # Mongoid.logger = Logger.new($stdout)
10
+ # Mongoid.load!('config/mongoid.yml')
11
+ #
12
+ # # Initialize SymmetricEncryption in a standalone environment. In a Rails app this is not required
13
+ # SymmetricEncryption.load!('config/symmetric-encryption.yml', 'test')
14
+ #
15
+ # class Person
16
+ # include Mongoid::Document
17
+ #
18
+ # field :name, :type => String
19
+ # field :encrypted_social_security_number, :type => String, :encrypted => true
20
+ # field :age, :type => Integer
21
+ # field :encrypted_life_history, :type => String, :encrypted => {:compress => true, :random_iv => true}
22
+ # end
23
+ #
24
+ # The above document results in the following document in the Mongo collection 'persons':
25
+ # {
26
+ # "name" : "Joe",
27
+ # "encrypted_social_security_number" : "...",
28
+ # "age" : 21
29
+ # "encrypted_life_history" : "...",
30
+ # }
31
+ #
32
+ # Symmetric Encryption creates the getters and setters to be able to work with the field
33
+ # in it's unencrypted form. For example
34
+ #
35
+ # Example:
36
+ # person = Person.where(:encrypted_social_security_number => '...').first
37
+ #
38
+ # puts "Decrypted Social Security Number is: #{person.social_security_number}"
39
+ #
40
+ # # Or is the same as
41
+ # puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
42
+ #
43
+ # # Sets the encrypted_social_security_number to encrypted version
44
+ # person.social_security_number = "123456789"
45
+ #
46
+ # # Or, is equivalent to:
47
+ # person.encrypted_social_security_number = SymmetricEncryption.encrypt("123456789")
48
+ #
49
+ # Note: Only "String" types are currently supported for encryption
50
+ #
51
+ # Note: Unlike attr_encrypted finders must use the encrypted field name
52
+ # Invalid Example, does not work:
53
+ # person = Person.where(:social_security_number => '123456789').first
54
+ #
55
+ # Valid Example:
56
+ # person = Person.where(:encrypted_social_security_number => SymmetricEncryption.encrypt('123456789')).first
57
+ #
58
+ # Defines all the fields that are accessible on the Document
59
+ # For each field that is defined, a getter and setter will be
60
+ # added as an instance method to the Document.
61
+ #
62
+ # @example Define a field.
63
+ # field :social_security_number, :type => String, :encrypted => {:compress => false, :random_iv => false}
64
+ # field :sensitive_text, :type => String, :encrypted => {:compress => true, :random_iv => true}
65
+ #
66
+ # @param [ Symbol ] name The name of the field.
67
+ # @param [ Hash ] options The options to pass to the field.
68
+ #
69
+ # @option options [ Boolean | Hash ] :encrypted If the field contains encrypted data.
70
+ # @option options [ Symbol ] :decrypt_as Name of the getters and setters to generate to access the decrypted value of this field.
71
+ # @option options [ Boolean ] :compress Whether to compress this encrypted field
72
+ # @option options [ Boolean ] :random_iv Whether the encrypted value should use a random IV every time the field is encrypted.
73
+ #
74
+ # @option options [ Class ] :type The type of the field.
75
+ # @option options [ String ] :label The label for the field.
76
+ # @option options [ Object, Proc ] :default The fields default
77
+ #
78
+ # @return [ Field ] The generated field
79
+ Mongoid::Fields.option :encrypted do |model, field, options|
80
+ if options != false
81
+ options = options.is_a?(Hash) ? options.dup : {}
82
+ field_name = field.name
83
+
84
+ decrypt_as = options.delete(:decrypt_as)
85
+ if decrypt_as.nil? && field_name.to_s.start_with?('encrypted_')
86
+ decrypt_as = field_name.to_s['encrypted_'.length..-1]
87
+ else
88
+ raise "SymmetricEncryption for Mongoid. Encryption enabled for field #{field_name}. It must either start with 'encrypted_' or the option :decrypt_as must be supplied"
89
+ end
90
+
91
+ random_iv = options.delete(:random_iv) || false
92
+ compress = options.delete(:compress) || false
93
+
94
+ # Generate getter and setter methods
95
+ model.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
96
+ # Set the un-encrypted field
97
+ # Also updates the encrypted field with the encrypted value
98
+ def #{decrypt_as}=(value)
99
+ @stored_#{field_name} = ::SymmetricEncryption.encrypt(value,#{random_iv},#{compress})
100
+ self.#{field_name} = @stored_#{field_name}
101
+ @#{decrypt_as} = value.freeze
102
+ end
103
+
104
+ # Returns the decrypted value for the encrypted field
105
+ # The decrypted value is cached and is only decrypted if the encrypted value has changed
106
+ # If this method is not called, then the encrypted value is never decrypted
107
+ def #{decrypt_as}
108
+ if @stored_#{field_name} != self.#{field_name}
109
+ @#{decrypt_as} = ::SymmetricEncryption.decrypt(self.#{field_name}).freeze
110
+ @stored_#{field_name} = self.#{field_name}
111
+ end
112
+ @#{decrypt_as}
113
+ end
114
+ EOS
115
+ end
116
+ end
117
+
118
+
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module SymmetricEncryption #:nodoc
3
- VERSION = "2.0.2"
3
+ VERSION = "2.2.0"
4
4
  end
File without changes
@@ -0,0 +1 @@
1
+ platform.active=Ruby_2
@@ -5,11 +5,12 @@ require 'rubygems'
5
5
  require 'logger'
6
6
  require 'erb'
7
7
  require 'test/unit'
8
- require 'shoulda'
9
8
  # Since we want both the AR and Mongoid extensions loaded we need to require them first
10
9
  require 'active_record'
11
10
  require 'mongoid'
12
11
  require 'symmetric-encryption'
12
+ # Should redefines Proc#bind so must include after Rails
13
+ require 'shoulda'
13
14
 
14
15
  ActiveRecord::Base.logger = Logger.new($stderr)
15
16
  ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read('test/config/database.yml')).result)
@@ -63,11 +64,14 @@ class AttrEncryptedTest < Test::Unit::TestCase
63
64
  @string = "A string containing some data to be encrypted with a random initialization vector"
64
65
  @long_string = "A string containing some data to be encrypted with a random initialization vector and compressed since it takes up so much space in plain text form"
65
66
 
67
+ @name = 'Joe Bloggs'
68
+
66
69
  @user = User.new(
67
70
  # Encrypted Attribute
68
- :bank_account_number => @bank_account_number,
71
+ :bank_account_number => @bank_account_number,
69
72
  # Encrypted Attribute
70
- :social_security_number => @social_security_number
73
+ :social_security_number => @social_security_number,
74
+ :name => @name
71
75
  )
72
76
  end
73
77
 
@@ -196,6 +200,54 @@ class AttrEncryptedTest < Test::Unit::TestCase
196
200
  assert_equal true, @user.valid?
197
201
  end
198
202
 
199
- end
203
+ context "with saved user" do
204
+ setup do
205
+ @user.save!
206
+ end
207
+
208
+ teardown do
209
+ @user.destroy
210
+ end
211
+
212
+ should "handle gsub! for non-encrypted_field" do
213
+ @user.name.gsub!('a', 'v')
214
+ new_name = @name.gsub('a', 'v')
215
+ assert_equal new_name, @user.name
216
+ @user.reload
217
+ assert_equal new_name, @user.name
218
+ end
219
+
220
+ should "prevent gsub! on non-encrypted value of encrypted_field" do
221
+ # can't modify frozen String
222
+ assert_raises RuntimeError do
223
+ @user.bank_account_number.gsub!('5', '4')
224
+ end
225
+ end
226
+
227
+ should "revert changes on reload" do
228
+ new_bank_account_number = '444444444'
229
+ @user.bank_account_number = new_bank_account_number
230
+ assert_equal new_bank_account_number, @user.bank_account_number
231
+
232
+ # Reload User model from the database
233
+ @user.reload
234
+ assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
235
+ assert_equal @bank_account_number, @user.bank_account_number
236
+ end
237
+
238
+ should "revert changes to encrypted field on reload" do
239
+ new_bank_account_number = '111111111'
240
+ new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
241
+ @user.encrypted_bank_account_number = new_encrypted_bank_account_number
242
+ assert_equal new_encrypted_bank_account_number, @user.encrypted_bank_account_number
243
+ assert_equal new_bank_account_number, @user.bank_account_number
244
+
245
+ # Reload User model from the database
246
+ @user.reload
247
+ assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
248
+ assert_equal @bank_account_number, @user.bank_account_number
249
+ end
250
+ end
200
251
 
252
+ end
201
253
  end
@@ -10,7 +10,6 @@ require 'shoulda'
10
10
  require 'active_record'
11
11
  require 'mongoid'
12
12
  require 'symmetric-encryption'
13
- require 'symmetric_encryption/extensions/mongoid/fields'
14
13
 
15
14
  Mongoid.logger = Logger.new($stdout)
16
15
  filename = defined?(Mongoid::VERSION) ? "test/config/mongoid_v3.yml" : "test/config/mongoid_v2.yml"
@@ -22,12 +21,8 @@ class MongoidUser
22
21
  field :name, :type => String
23
22
  field :encrypted_bank_account_number, :type => String, :encrypted => true
24
23
  field :encrypted_social_security_number, :type => String, :encrypted => true
25
- field :encrypted_string, :type => String, :encrypted => true, :random_iv => true
26
- field :encrypted_long_string, :type => String, :encrypted => true, :random_iv => true, :compress => true
27
- # field :encrypted_integer, :type => Integer, :encrypted => true
28
- # field :encrypted_float, :type => Float, :encrypted => true
29
- # field :encrypted_date, :type => Date, :encrypted => true
30
- # etc...
24
+ field :encrypted_string, :type => String, :encrypted => {:random_iv => true}
25
+ field :encrypted_long_string, :type => String, :encrypted => {:random_iv => true, :compress => true}
31
26
 
32
27
  # validates :encrypted_bank_account_number, :symmetric_encrypted => true
33
28
  # validates :encrypted_social_security_number, :symmetric_encrypted => true
@@ -64,19 +59,36 @@ class FieldEncryptedTest < Test::Unit::TestCase
64
59
  @user = MongoidUser.new(
65
60
  :encrypted_bank_account_number => @bank_account_number_encrypted,
66
61
  :encrypted_social_security_number => @social_security_number_encrypted,
67
- :encrypted_integer => @integer_encrypted,
68
- :encrypted_float => @float_encrypted,
69
- :encrypted_date => @date_encrypted,
70
62
  :name => "Joe Bloggs"
71
63
  )
72
64
  end
73
65
 
74
66
  should "have encrypted methods" do
75
67
  assert_equal true, @user.respond_to?(:encrypted_bank_account_number)
76
- assert_equal true, @user.respond_to?(:bank_account_number)
77
68
  assert_equal true, @user.respond_to?(:encrypted_social_security_number)
78
- assert_equal true, @user.respond_to?(:social_security_number)
69
+ assert_equal true, @user.respond_to?(:encrypted_string)
70
+ assert_equal true, @user.respond_to?(:encrypted_long_string)
79
71
  assert_equal false, @user.respond_to?(:encrypted_name)
72
+
73
+ assert_equal true, @user.respond_to?(:encrypted_bank_account_number=)
74
+ assert_equal true, @user.respond_to?(:encrypted_social_security_number=)
75
+ assert_equal true, @user.respond_to?(:encrypted_string=)
76
+ assert_equal true, @user.respond_to?(:encrypted_long_string=)
77
+ assert_equal false, @user.respond_to?(:encrypted_name=)
78
+ end
79
+
80
+ should "have unencrypted methods" do
81
+ assert_equal true, @user.respond_to?(:bank_account_number)
82
+ assert_equal true, @user.respond_to?(:social_security_number)
83
+ assert_equal true, @user.respond_to?(:string)
84
+ assert_equal true, @user.respond_to?(:long_string)
85
+ assert_equal true, @user.respond_to?(:name)
86
+
87
+ assert_equal true, @user.respond_to?(:bank_account_number=)
88
+ assert_equal true, @user.respond_to?(:social_security_number=)
89
+ assert_equal true, @user.respond_to?(:string=)
90
+ assert_equal true, @user.respond_to?(:long_string=)
91
+ assert_equal true, @user.respond_to?(:name=)
80
92
  end
81
93
 
82
94
  should "have unencrypted values" do
@@ -156,11 +168,6 @@ class FieldEncryptedTest < Test::Unit::TestCase
156
168
  assert_equal @bank_account_number_encrypted, user.encrypted_bank_account_number
157
169
  assert_equal @social_security_number_encrypted, user.encrypted_social_security_number
158
170
  end
159
-
160
- # should "support different data types" do
161
- # assert_equal @integer, @user.integer
162
- # assert_equal @integer_encrypted, @user.encrypted_integer
163
- # end
164
171
  end
165
172
 
166
173
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: symmetric-encryption
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-26 00:00:00.000000000 Z
11
+ date: 2013-07-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: SymmetricEncryption supports encrypting ActiveRecord data, Mongoid data,
14
14
  passwords in configuration files, encrypting and decrypting of large files through
@@ -32,7 +32,7 @@ files:
32
32
  - lib/symmetric_encryption.rb
33
33
  - lib/symmetric_encryption/cipher.rb
34
34
  - lib/symmetric_encryption/extensions/active_record/base.rb
35
- - lib/symmetric_encryption/extensions/mongoid/fields.rb
35
+ - lib/symmetric_encryption/mongoid.rb
36
36
  - lib/symmetric_encryption/railtie.rb
37
37
  - lib/symmetric_encryption/railties/symmetric_encryption.rake
38
38
  - lib/symmetric_encryption/railties/symmetric_encryption_validator.rb
@@ -40,6 +40,8 @@ files:
40
40
  - lib/symmetric_encryption/symmetric_encryption.rb
41
41
  - lib/symmetric_encryption/version.rb
42
42
  - lib/symmetric_encryption/writer.rb
43
+ - nbproject/private/config.properties
44
+ - nbproject/private/private.properties
43
45
  - nbproject/private/private.xml
44
46
  - nbproject/private/rake-d.txt
45
47
  - nbproject/project.properties
@@ -1,135 +0,0 @@
1
- # Extensions to the mongoid Document model to support field encryption
2
- # per the attr_encrypted model
3
- #
4
- #
5
- # #TODO initialize, create
6
- #
7
- module Mongoid
8
- module Fields
9
- module ClassMethods
10
- # Example:
11
- #
12
- # require 'mongoid'
13
- # require 'symmetric-encryption'
14
- #
15
- # # Initialize Mongoid in a standalone environment. In a Rails app this is not required
16
- # Mongoid.logger = Logger.new($stdout)
17
- # Mongoid.load!('config/mongoid.yml')
18
- #
19
- # # Initialize SymmetricEncryption in a standalone environment. In a Rails app this is not required
20
- # SymmetricEncryption.load!('config/symmetric-encryption.yml', 'test')
21
- #
22
- # class Person
23
- # include Mongoid::Document
24
- #
25
- # field :name, :type => String
26
- # field :encrypted_social_security_number, :type => String, :encrypted => true
27
- # field :age, :type => Integer
28
- # field :encrypted_life_history, :type => String, :encrypted => true, :compress => true, :random_iv => true
29
- # end
30
- #
31
- # The above document results in the following document in the Mongo collection 'persons':
32
- # {
33
- # "name" : "Joe",
34
- # "encrypted_social_security_number" : "...",
35
- # "age" : 21
36
- # "encrypted_life_history" : "...",
37
- # }
38
- #
39
- # Symmetric Encryption creates the getters and setters to be able to work with the field
40
- # in it's unencrypted form. For example
41
- #
42
- # Example:
43
- # person = Person.where(:encrypted_social_security_number => '...').first
44
- #
45
- # puts "Decrypted Social Security Number is: #{person.social_security_number}"
46
- #
47
- # # Or is the same as
48
- # puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
49
- #
50
- # # Sets the encrypted_social_security_number to encrypted version
51
- # person.social_security_number = "123456789"
52
- #
53
- # # Or, is equivalent to:
54
- # person.encrypted_social_security_number = SymmetricEncryption.encrypt("123456789")
55
- #
56
- #
57
- # Note: Unlike attr_encrypted finders must use the encrypted field name
58
- # Invalid Example, does not work:
59
- # person = Person.where(:social_security_number => '123456789').first
60
- #
61
- # Valid Example:
62
- # person = Person.where(:encrypted_social_security_number => SymmetricEncryption.encrypt('123456789')).first
63
- #
64
- # Defines all the fields that are accessible on the Document
65
- # For each field that is defined, a getter and setter will be
66
- # added as an instance method to the Document.
67
- #
68
- # @example Define a field.
69
- # field :social_security_number, :type => String, :encrypted => true, :compress => false, :random_iv => false
70
- # field :sensitive_text, :type => String, :encrypted => true, :compress => true, :random_iv => true
71
- #
72
- # @param [ Symbol ] name The name of the field.
73
- # @param [ Hash ] options The options to pass to the field.
74
- #
75
- # @option options [ Boolean ] :encrypted If the field contains encrypted data.
76
- # @option options [ Symbol ] :decrypt_as Name of the getters and setters to generate to access the decrypted value of this field.
77
- # @option options [ Boolean ] :compress Whether to compress this encrypted field
78
- # @option options [ Boolean ] :random_iv Whether the encrypted value should use a random IV every time the field is encrypted.
79
- #
80
- # @option options [ Class ] :type The type of the field.
81
- # @option options [ String ] :label The label for the field.
82
- # @option options [ Object, Proc ] :default The fields default
83
- #
84
- # @return [ Field ] The generated field
85
- def field_with_symmetric_encryption(field_name, options={})
86
- if options.delete(:encrypted) == true
87
- decrypt_as = options.delete(:decrypt_as)
88
- unless decrypt_as
89
- raise "SymmetricEncryption for Mongoid. When encryption is enabled for a field it must either start with 'encrypted_' or the option :decrypt must be supplied" unless field_name.to_s.start_with?('encrypted_')
90
- decrypt_as = field_name.to_s['encrypted_'.length..-1]
91
- end
92
-
93
- random_iv = options.delete(:random_iv) || false
94
- compress = options.delete(:compress) || false
95
-
96
- # Store Intended data type for this field, but we store it as a String
97
- underlying_type = options[:type]
98
- options[:type] = String
99
-
100
- raise "SymmetricEncryption for Mongoid currently only supports :type => String" unless underlying_type == String
101
-
102
- # #TODO Need to do type conversions. Currently only supports String
103
-
104
- # Generate getter and setter methods
105
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
106
- # Set the un-encrypted field
107
- # Also updates the encrypted field with the encrypted value
108
- def #{decrypt_as}=(value)
109
- @stored_#{field_name} = ::SymmetricEncryption.encrypt(value,#{random_iv},#{compress})
110
- self.#{field_name} = @stored_#{field_name}
111
- @#{decrypt_as} = value
112
- end
113
-
114
- # Returns the decrypted value for the encrypted field
115
- # The decrypted value is cached and is only decrypted if the encrypted value has changed
116
- # If this method is not called, then the encrypted value is never decrypted
117
- def #{decrypt_as}
118
- if @stored_#{field_name} != self.#{field_name}
119
- @#{decrypt_as} = ::SymmetricEncryption.decrypt(self.#{field_name})
120
- @stored_#{field_name} = self.#{field_name}
121
- end
122
- @#{decrypt_as}
123
- end
124
- EOS
125
- end
126
-
127
- # Pass on to the regular Mongoid field method
128
- field_without_symmetric_encryption(field_name, options)
129
- end
130
- alias_method_chain :field, :symmetric_encryption
131
-
132
- end
133
-
134
- end
135
- end