symmetric-encryption 2.0.2 → 2.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.
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