sidekiq-field-encryptor 0.1.1 → 0.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
- SHA1:
3
- metadata.gz: d7b580f10f55bd99cc1b08a0d41157746562b155
4
- data.tar.gz: d93bb7059b52325809a24f161c98ec4b705f9323
2
+ SHA256:
3
+ metadata.gz: c11c669792764e011bd552df7369298eaa77961b1e83c55047c172db8bce861e
4
+ data.tar.gz: 2d3604aa814fc4baa6b2597a16231348de41b5bb36efe3946ee7b3b6cfe2cf47
5
5
  SHA512:
6
- metadata.gz: 73208766812240af540b2fac93f98f4d585ffb0065dda731dbd47be7b01ee4d4b8eab048925c2254c465ce46ecaf0a775ffb6a6e010c1b52d429f04119992f02
7
- data.tar.gz: 04f77a80f08b85d429c804a38b2244a4f5f564cd6a4a5e7704fb9727796261d7280a0fc47f80a4d3f593d9a6940be13f9b397c6d4f930a38eb294440012aa048
6
+ metadata.gz: 6d7468111be23b540a4a3e1ed44771097902bef7a591a3c67ae0ad9a6a609402567f299f575eff127f3862f35d191c7c959d8cd44c618bc33a116031cff5d224
7
+ data.tar.gz: fb7827f9988d5ec43d124fcc9f08481cb4ebda5bfd5ddf80836c03cbef64e7954ef1db6a3efb485c2cd18f1856d5866324fd06d0f2b2010c7ca6a3e121a8f7ce
@@ -1,5 +1,6 @@
1
1
  require 'base64'
2
2
  require 'encryptor'
3
+ require 'json'
3
4
  require 'sidekiq-field-encryptor/version'
4
5
 
5
6
  # This middleware configures encryption of any fields that can contain sensitive
@@ -21,30 +22,69 @@ require 'sidekiq-field-encryptor/version'
21
22
  # Will encrypt the values {'x' => 1} and 'b' when storing the job in Redis and
22
23
  # decrypt the values inside the client before the job is executed.
23
24
  module SidekiqFieldEncryptor
25
+ SERIALIZE_JSON = 'json'.freeze
26
+ SERIALIZE_MARHSALL = 'marshal'.freeze
27
+
24
28
  class Base
25
29
  def initialize(options = {})
26
30
  @encryption_key = options[:encryption_key]
27
31
  @encrypted_fields = options[:encrypted_fields] || {}
28
32
  @encryption_algorithm = options[:encryption_algorithm] || 'aes-256-gcm'
33
+
34
+ @serialization_method = options[:serialization_method] || SERIALIZE_JSON
35
+ @serialization_compat = options[:serialization_compat]
29
36
  end
30
37
 
31
38
  def assert_key_configured
32
39
  raise 'Encryption key not configured' if @encryption_key.nil?
33
40
  end
34
41
 
42
+ def serialize(value)
43
+ case @serialization_method
44
+ when SERIALIZE_JSON
45
+ JSON.generate(value, quirks_mode: true)
46
+ when SERIALIZE_MARHSALL
47
+ Marshal.dump(value)
48
+ else
49
+ raise "Invalid serialization_method: #{@serialization_method}"
50
+ end
51
+ end
52
+
53
+ def deserialize(method, value)
54
+ if !@serialization_compat && method != @serialization_method
55
+ raise "Invalid serialization_method received: #{method}"
56
+ end
57
+
58
+ case method
59
+ when SERIALIZE_JSON
60
+ JSON.parse(value, quirks_mode: true)
61
+ when SERIALIZE_MARHSALL, nil
62
+ # No method used to be Marshall, so we respect this here
63
+ Marshal.load(value)
64
+ else
65
+ raise "Invalid serialization_method: #{@serialization_method}"
66
+ end
67
+ end
68
+
35
69
  def encrypt(value)
36
- plaintext = Marshal.dump(value)
70
+ plaintext = serialize(value)
37
71
  iv = OpenSSL::Cipher::Cipher.new(@encryption_algorithm).random_iv
38
72
  args = { key: @encryption_key, iv: iv, algorithm: @encryption_algorithm }
39
73
  ciphertext = ::Encryptor.encrypt(plaintext, **args)
40
- [::Base64.encode64(ciphertext), ::Base64.encode64(iv)]
74
+ [
75
+ ::Base64.encode64(ciphertext),
76
+ ::Base64.encode64(iv),
77
+ @serialization_method
78
+ ]
41
79
  end
42
80
 
43
81
  def decrypt(encrypted)
44
- ciphertext, iv = encrypted.map { |value| ::Base64.decode64(value) }
82
+ base64_ciphertext, base64_iv, serialization_method = encrypted
83
+ ciphertext = ::Base64.decode64(base64_ciphertext)
84
+ iv = ::Base64.decode64(base64_iv)
45
85
  args = { key: @encryption_key, iv: iv, algorithm: @encryption_algorithm }
46
86
  plaintext = ::Encryptor.decrypt(ciphertext, **args)
47
- Marshal.load(plaintext)
87
+ deserialize(serialization_method, plaintext)
48
88
  end
49
89
 
50
90
  def process_message(message)
@@ -1,3 +1,3 @@
1
1
  module SidekiqFieldEncryptor
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
@@ -117,5 +117,41 @@ describe SidekiqFieldEncryptor::Server do
117
117
 
118
118
  ok.call('FooJob', message, nil) {}
119
119
  end
120
+
121
+ it 'fails if the serialization methods are different' do
122
+ r = SidekiqFieldEncryptor::Server.new(
123
+ encryption_key: key,
124
+ encrypted_fields: { 'FooJob' => { 1 => true } },
125
+ serialization_method: SidekiqFieldEncryptor::SERIALIZE_JSON
126
+ )
127
+
128
+ e = SidekiqFieldEncryptor::Client.new(
129
+ encryption_key: key,
130
+ encrypted_fields: { 'FooJob' => { 1 => true } },
131
+ serialization_method: SidekiqFieldEncryptor::SERIALIZE_MARHSALL
132
+ )
133
+
134
+ message['args'][1] = e.encrypt(message['args'][1])
135
+ expect { r.call('FooJob', message, nil) {} }
136
+ .to raise_error(/invalid serialization_method/i)
137
+ end
138
+
139
+ it 'allows compat serialization' do
140
+ r = SidekiqFieldEncryptor::Server.new(
141
+ encryption_key: key,
142
+ encrypted_fields: { 'FooJob' => { 1 => true } },
143
+ serialization_method: SidekiqFieldEncryptor::SERIALIZE_JSON,
144
+ serialization_compat: true
145
+ )
146
+
147
+ e = SidekiqFieldEncryptor::Client.new(
148
+ encryption_key: key,
149
+ encrypted_fields: { 'FooJob' => { 1 => true } },
150
+ serialization_method: SidekiqFieldEncryptor::SERIALIZE_MARHSALL
151
+ )
152
+
153
+ message['args'][1] = e.encrypt(message['args'][1])
154
+ r.call('FooJob', message, nil) {}
155
+ end
120
156
  end
121
157
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-field-encryptor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Pettersson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-02 00:00:00.000000000 Z
11
+ date: 2018-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: encryptor
@@ -120,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  version: '0'
121
121
  requirements: []
122
122
  rubyforge_project:
123
- rubygems_version: 2.4.5.1
123
+ rubygems_version: 2.7.6
124
124
  signing_key:
125
125
  specification_version: 4
126
126
  summary: Selectively encrypt fields sent into Sidekiq