crypt_keeper 0.8.0 → 0.9.0.pre
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/gemfiles/activerecord_3_0.gemfile.lock +1 -1
- data/gemfiles/activerecord_3_1.gemfile.lock +1 -1
- data/gemfiles/activerecord_3_2.gemfile.lock +1 -1
- data/lib/crypt_keeper/model.rb +33 -1
- data/lib/crypt_keeper/provider/aes.rb +1 -3
- data/lib/crypt_keeper/version.rb +1 -1
- data/spec/model_spec.rb +28 -0
- data/spec/support/encryptors.rb +1 -1
- metadata +6 -9
data/lib/crypt_keeper/model.rb
CHANGED
@@ -17,11 +17,31 @@ module CryptKeeper
|
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
+
# Private: A hash of encrypted attributes with their encrypted values
|
21
|
+
#
|
22
|
+
# Returns a Hash
|
23
|
+
def crypt_keeper_dirty_tracking
|
24
|
+
@crypt_keeper_dirty_tracking ||= HashWithIndifferentAccess.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Private: Determine if the field's plaintext value changed. It compares
|
28
|
+
# it to the original value that came from the DB before decryption
|
29
|
+
#
|
30
|
+
# Returns boolean
|
31
|
+
def plaintext_changed?(field)
|
32
|
+
new_record? || self[field] != self.class.decrypt(crypt_keeper_dirty_tracking[field])
|
33
|
+
end
|
34
|
+
|
20
35
|
# Private: Encrypt each crypt_keeper_fields
|
21
36
|
def encrypt_callback
|
22
37
|
crypt_keeper_fields.each do |field|
|
23
38
|
if !self[field].nil?
|
24
|
-
|
39
|
+
if plaintext_changed?(field)
|
40
|
+
self[field] = self.class.encrypt read_attribute(field)
|
41
|
+
else
|
42
|
+
self[field] = crypt_keeper_dirty_tracking[field]
|
43
|
+
clear_field_changes! field
|
44
|
+
end
|
25
45
|
end
|
26
46
|
end
|
27
47
|
end
|
@@ -30,8 +50,11 @@ module CryptKeeper
|
|
30
50
|
def decrypt_callback
|
31
51
|
crypt_keeper_fields.each do |field|
|
32
52
|
if !self[field].nil?
|
53
|
+
crypt_keeper_dirty_tracking[field] = read_attribute(field)
|
33
54
|
self[field] = self.class.decrypt read_attribute(field)
|
34
55
|
end
|
56
|
+
|
57
|
+
clear_field_changes! field
|
35
58
|
end
|
36
59
|
end
|
37
60
|
|
@@ -42,6 +65,15 @@ module CryptKeeper
|
|
42
65
|
end
|
43
66
|
end
|
44
67
|
|
68
|
+
# Private: Removes changes from `#previous_changes` and
|
69
|
+
# `#changed_attributes` so the model isn't considered dirty.
|
70
|
+
#
|
71
|
+
# field - The field to clear
|
72
|
+
def clear_field_changes!(field)
|
73
|
+
previous_changes.delete(field.to_s)
|
74
|
+
changed_attributes.delete(field.to_s)
|
75
|
+
end
|
76
|
+
|
45
77
|
module ClassMethods
|
46
78
|
# Public: Setup fields for encryption
|
47
79
|
#
|
@@ -33,9 +33,7 @@ module CryptKeeper
|
|
33
33
|
def encrypt(value)
|
34
34
|
aes.encrypt
|
35
35
|
aes.key = key
|
36
|
-
|
37
|
-
aes.iv = iv
|
38
|
-
Base64::encode64("#{iv}#{SEPARATOR}#{aes.update(value.to_s) + aes.final}")
|
36
|
+
Base64::encode64("#{aes.random_iv}#{SEPARATOR}#{aes.update(value.to_s) + aes.final}")
|
39
37
|
end
|
40
38
|
|
41
39
|
# Public: Decrypt a string
|
data/lib/crypt_keeper/version.rb
CHANGED
data/spec/model_spec.rb
CHANGED
@@ -118,6 +118,34 @@ module CryptKeeper
|
|
118
118
|
SensitiveData.crypt_keeper_options.should include(passphrase: 'tool')
|
119
119
|
end
|
120
120
|
end
|
121
|
+
|
122
|
+
describe "Dirty records" do
|
123
|
+
before do
|
124
|
+
SensitiveData.crypt_keeper :storage, passphrase: 'tool', encryptor: :postgres_pgp
|
125
|
+
end
|
126
|
+
|
127
|
+
let(:record) do
|
128
|
+
SensitiveData.create storage: 'test'
|
129
|
+
end
|
130
|
+
|
131
|
+
specify { record.should_not be_changed }
|
132
|
+
|
133
|
+
it "unchanged plaintext does not trigger a save" do
|
134
|
+
queries = []
|
135
|
+
|
136
|
+
subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |name, started, finished, id, payload|
|
137
|
+
queries << payload[:sql]
|
138
|
+
end
|
139
|
+
|
140
|
+
SensitiveData.find(record.id).save
|
141
|
+
ActiveSupport::Notifications.unsubscribe subscriber
|
142
|
+
|
143
|
+
updates = queries.select { |query| query.match(/^UPDATE /) }
|
144
|
+
|
145
|
+
queries.should_not be_empty
|
146
|
+
updates.should be_empty, "Received #{updates}"
|
147
|
+
end
|
148
|
+
end
|
121
149
|
end
|
122
150
|
end
|
123
151
|
end
|
data/spec/support/encryptors.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crypt_keeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.9.0.pre
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Justin Mazzi
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -243,16 +243,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
243
243
|
version: '0'
|
244
244
|
segments:
|
245
245
|
- 0
|
246
|
-
hash:
|
246
|
+
hash: 3463799705679216715
|
247
247
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
248
248
|
none: false
|
249
249
|
requirements:
|
250
|
-
- - ! '
|
250
|
+
- - ! '>'
|
251
251
|
- !ruby/object:Gem::Version
|
252
|
-
version:
|
253
|
-
segments:
|
254
|
-
- 0
|
255
|
-
hash: 838883882659964076
|
252
|
+
version: 1.3.1
|
256
253
|
requirements: []
|
257
254
|
rubyforge_project:
|
258
255
|
rubygems_version: 1.8.24
|