crypt_keeper 0.8.0 → 0.9.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|