mongoid-kms 0.0.14 → 0.0.15

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: 49b32845a5b6f1ca1f9d205d59915df58e7425e1
4
- data.tar.gz: 1c9dbdf7f83534f9b1f94d7e1e03e83d1aef930f
3
+ metadata.gz: 029a4f6efe9f5dafce5aef2c5fab0801229f04cc
4
+ data.tar.gz: 749be3c2641a52cebab3d4f7f2e8d1491a765649
5
5
  SHA512:
6
- metadata.gz: 85e1bf962a3660b1bd10f844c117383fb590c8777f5575e012fa1cb85a9526ef822d0c9d4066862301928fdb696009faf92ed6c7a8b86dd07387f598cf47580f
7
- data.tar.gz: dd9bfa5812eccc83711c2c39538558e39a4f9950af12ee93c73cdba7d370b3acb1e8cc36cd2b8ea4a97783033b21b8ef93ea483355a6d7332a6828c2b8c62205
6
+ metadata.gz: b1386752d377273539f4f06130d820316d7398e10aac8303b7794d84015c95213b2ad5d909ff64a77516a5491f2f9878c04957d78888f93dcc5c36808eac8f27
7
+ data.tar.gz: 759ce38aba35b4d9b49401e2b3cb08f64ef4017c832bf7b6608bd09b9caac659228d44517a9a0e0eac480fbdfca5167ee51095cb3245cfb4078656b99b3405bb
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Kms
3
- VERSION = "0.0.14"
3
+ VERSION = "0.0.15"
4
4
  end
5
5
  end
data/lib/mongoid/kms.rb CHANGED
@@ -6,73 +6,144 @@ module Mongoid
6
6
  module Kms
7
7
  extend ActiveSupport::Concern
8
8
 
9
+ included do
10
+ @kms_field_map ||= {}
11
+
12
+ unless self.ancestors.include?(ActiveModel::Dirty)
13
+ include ActiveModel::Dirty
14
+ end
15
+ end
16
+
9
17
  @configuration = {}
10
18
  @kms = nil
11
19
 
12
- def self.configure(args)
13
- @configuration = args
14
- end
20
+ # Module methods
21
+ class << self
22
+ def configure(args)
23
+ @configuration = args
24
+ end
15
25
 
16
- def self.configuration
17
- @configuration || {}
18
- end
26
+ def configuration
27
+ @configuration || {}
28
+ end
19
29
 
20
- def self.kms
21
- @kms ||= Aws::KMS::Client.new(region: self.region)
22
- end
30
+ def kms
31
+ @kms ||= Aws::KMS::Client.new(region: self.region)
32
+ end
23
33
 
24
- def self.region
25
- configuration[:region]
26
- end
34
+ def region
35
+ configuration[:region]
36
+ end
37
+
38
+ def key
39
+ configuration[:key]
40
+ end
27
41
 
28
- def self.key
29
- configuration[:key]
42
+ def bson_class
43
+ if defined? Moped::BSON
44
+ Moped::BSON
45
+ elsif defined? BSON
46
+ BSON
47
+ end
48
+ end
30
49
  end
31
50
 
32
- def self.bson_class
33
- if defined? Moped::BSON
34
- Moped::BSON
35
- elsif defined? BSON
36
- BSON
51
+ # Instance methods
52
+ def set_kms_values
53
+ self.class.kms_field_map.each do |field_name, settings|
54
+ if self.send("#{field_name}_changed?") || kms_context_value_changed?(field_name)
55
+ encrypted_field_name = self.class.get_encrypted_field_name(field_name)
56
+
57
+ if instance_variable_get("@#{field_name}").nil? && kms_context_value_changed?(field_name)
58
+ value = self.class.decrypt_field(self, field_name, self.send(encrypted_field_name), self.class.kms_context_was(self, field_name))
59
+ else
60
+ value = send("#{field_name}")
61
+ end
62
+
63
+ if value.nil?
64
+ self.send("#{encrypted_field_name}=", nil)
65
+ else
66
+ self.send("#{encrypted_field_name}=", self.class.encrypt_field(self, field_name, value))
67
+ end
68
+ end
37
69
  end
38
70
  end
39
71
 
72
+ def kms_context_value_changed?(field_name)
73
+ self.class.kms_context_array(self, field_name).find { |f| self.respond_to?(f) && self.send("#{f}_changed?") }
74
+ end
75
+
76
+ # Class methods
40
77
  module ClassMethods
78
+ def kms_field_map
79
+ @kms_field_map
80
+ end
81
+
41
82
  def encrypt_field(object, field_name, value)
42
83
  Mongoid::Kms.kms.encrypt({
43
84
  key_id: Mongoid::Kms.key,
44
85
  plaintext: value,
45
86
  encryption_context: kms_context(object, field_name)
46
87
  })[:ciphertext_blob].force_encoding('UTF-8')
47
- rescue ArgumentError
48
- raise "Error using KMS context. If you use an object's field for context, set your encrypted fields explicitly: myobject.#{field_name} = #{value.inspect}"
49
88
  end
50
89
 
51
- def decrypt_field(object, field_name, data)
90
+ def decrypt_field(object, field_name, data, encryption_context = nil)
91
+ encryption_context ||= kms_context(object, field_name)
92
+
52
93
  Mongoid::Kms.kms.decrypt({
53
94
  ciphertext_blob: data,
54
- encryption_context: kms_context(object, field_name)
95
+ encryption_context: encryption_context
55
96
  })[:plaintext]
56
97
  end
57
98
 
58
99
  def kms_context(object, field_name)
59
- c = @kms_field_map[field_name.to_s][:context]
60
- c = c.call(object) if c.is_a?(Proc)
61
- c
100
+ kms_context_array(object, field_name).inject({}) do |hash, key|
101
+ if object.respond_to?(key)
102
+ hash[key] = object.send(key)
103
+ else
104
+ hash[key] = key
105
+ end
106
+
107
+ hash
108
+ end
109
+ end
110
+
111
+ def kms_context_was(object, field_name)
112
+ kms_context_array(object, field_name).inject({}) do |hash, key|
113
+ if object.respond_to?("#{key}_was") && object.send("#{key}_changed?")
114
+ hash[key] = object.send("#{key}_was")
115
+ elsif object.respond_to?(key)
116
+ hash[key] = object.send(key)
117
+ else
118
+ hash[key] = key
119
+ end
120
+
121
+ hash
122
+ end
123
+ end
124
+
125
+ def kms_context_array(object, field_name)
126
+ @kms_field_map[field_name.to_s][:context] || []
62
127
  end
63
128
 
64
129
  def kms_type(field_name)
65
130
  @kms_field_map[field_name.to_s][:type]
66
131
  end
67
132
 
133
+ def get_encrypted_field_name(field_name)
134
+ "kms_secure_#{field_name}"
135
+ end
136
+
68
137
  def secure_field(field_name, args)
69
- encrypted_field_name = "kms_secure_#{field_name}"
138
+ encrypted_field_name = get_encrypted_field_name(field_name)
70
139
 
71
- @kms_field_map ||= {}
72
140
  @kms_field_map[field_name.to_s] = {context: args.delete(:context), type: args.delete(:type)}
73
141
 
74
142
  field encrypted_field_name, args.merge(type: Mongoid::Kms.bson_class::Binary)
75
143
 
144
+ define_attribute_methods field_name.to_sym
145
+ before_save :set_kms_values
146
+
76
147
  define_method(field_name) do
77
148
  instance_variable_get("@#{field_name}") || begin
78
149
  raw = send("kms_secure_#{field_name}")
@@ -88,13 +159,8 @@ module Mongoid
88
159
  end
89
160
 
90
161
  define_method("#{field_name}=") do |value|
162
+ self.send("#{field_name}_will_change!")
91
163
  instance_variable_set("@#{field_name}", value)
92
-
93
- if value.nil?
94
- self.send("#{encrypted_field_name}=", nil)
95
- else
96
- self.send("#{encrypted_field_name}=", self.class.encrypt_field(self, field_name, value))
97
- end
98
164
  end
99
165
  end
100
166
  end
@@ -3,8 +3,7 @@ require 'spec_helper'
3
3
  describe Mongoid::Kms do
4
4
 
5
5
  it "encrypts the secure fields" do
6
- o = MyClass.new(unsecure: "robin")
7
- o.secure = "batman"
6
+ o = MyClass.new(secure: "batman", unsecure: "robin")
8
7
  o.save!
9
8
 
10
9
  expect(o.secure).to eq("batman")
@@ -12,8 +11,7 @@ describe Mongoid::Kms do
12
11
  end
13
12
 
14
13
  it "descripts the secure fields" do
15
- o = MyClass.new(unsecure: "robin")
16
- o.secure = "batman"
14
+ o = MyClass.new(unsecure: "robin", secure: "batman")
17
15
  o.save!
18
16
 
19
17
  o = MyClass.find(o.id)
@@ -21,9 +19,8 @@ describe Mongoid::Kms do
21
19
  expect(o.unsecure).to eq("robin")
22
20
  end
23
21
 
24
- it "encrypts teh other fields" do
25
- o = OtherClass.new(unsecure: "pengiun")
26
- o.super_secure = "joker"
22
+ it "encrypts the other fields" do
23
+ o = OtherClass.new(unsecure: "pengiun", super_secure: "joker")
27
24
  o.save!
28
25
 
29
26
  o = OtherClass.find(o.id)
@@ -31,4 +28,24 @@ describe Mongoid::Kms do
31
28
  expect(o.unsecure).to eq("pengiun")
32
29
  end
33
30
 
31
+ it "modifies the encryption if the context field changes" do
32
+ o = MyClass.new(unsecure: "robin", secure: "other")
33
+ o.save!
34
+
35
+ o = MyClass.find(o.id)
36
+ o.unsecure = "bla"
37
+ o.save!
38
+
39
+ o = MyClass.find(o.id)
40
+ expect(o.secure).to eq("other")
41
+ end
42
+
43
+ it "handles a class without context" do
44
+ o = MyClass.new(secure: "bla", unsecure: "blatoo")
45
+ o.save!
46
+
47
+ o = MyClass.find(o.id)
48
+ expect(o.secure).to eq("bla")
49
+ end
50
+
34
51
  end
data/spec/spec_helper.rb CHANGED
@@ -9,7 +9,7 @@ class MyClass
9
9
  include Mongoid::Document
10
10
  include Mongoid::Kms
11
11
 
12
- secure_field :secure, type: String, context: lambda { |d| {name: d.unsecure} }
12
+ secure_field :secure, type: String, context: [:unsecure]
13
13
  field :unsecure
14
14
  end
15
15
 
@@ -17,9 +17,16 @@ class OtherClass
17
17
  include Mongoid::Document
18
18
  include Mongoid::Kms
19
19
 
20
- secure_field :super_secure, type: String, context: lambda { |d| {some_name: d.unsecure} }
20
+ secure_field :super_secure, type: String, context: [:unsecure, "deployment"]
21
21
  field :unsecure
22
22
  end
23
23
 
24
+ class ClassWithoutContext
25
+ include Mongoid::Document
26
+ include Mongoid::Kms
27
+
28
+ secure_field :secure, type: String
29
+ field :unsecure
30
+ end
24
31
 
25
32
  Mongoid::Kms.configure({region: "us-east-1", key: ENV['AWS_KMS_KEY_ID']})
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-kms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Winslett
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-13 00:00:00.000000000 Z
11
+ date: 2014-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid