pubnub 5.2.1 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -2
  3. data/.github/workflows/commands-handler.yml +18 -2
  4. data/.github/workflows/run-tests.yml +27 -17
  5. data/.github/workflows/run-validations.yml +12 -2
  6. data/.pubnub.yml +20 -4
  7. data/.tool-versions +1 -1
  8. data/CHANGELOG.md +15 -0
  9. data/Gemfile +1 -1
  10. data/Gemfile.lock +6 -6
  11. data/LICENSE +29 -0
  12. data/README.md +1 -1
  13. data/VERSION +1 -1
  14. data/features/step_definitions/access_steps.rb +0 -2
  15. data/features/step_definitions/crypto_steps.rb +99 -0
  16. data/features/support/cryptor.rb +58 -0
  17. data/features/support/hooks.rb +0 -1
  18. data/lib/pubnub/client.rb +30 -1
  19. data/lib/pubnub/error.rb +3 -0
  20. data/lib/pubnub/event.rb +13 -5
  21. data/lib/pubnub/events/add_message_action.rb +2 -2
  22. data/lib/pubnub/events/get_message_actions.rb +1 -1
  23. data/lib/pubnub/events/grant_token.rb +1 -1
  24. data/lib/pubnub/events/history.rb +18 -6
  25. data/lib/pubnub/events/publish.rb +7 -3
  26. data/lib/pubnub/events/remove_channel_members.rb +3 -3
  27. data/lib/pubnub/events/remove_channel_metadata.rb +1 -1
  28. data/lib/pubnub/events/remove_memberships.rb +3 -3
  29. data/lib/pubnub/events/remove_uuid_metadata.rb +1 -1
  30. data/lib/pubnub/events/set_channel_members.rb +3 -3
  31. data/lib/pubnub/events/set_channel_metadata.rb +2 -2
  32. data/lib/pubnub/events/set_memberships.rb +3 -3
  33. data/lib/pubnub/events/set_uuid_metadata.rb +2 -2
  34. data/lib/pubnub/events/signal.rb +1 -1
  35. data/lib/pubnub/events/subscribe.rb +5 -0
  36. data/lib/pubnub/formatter.rb +22 -11
  37. data/lib/pubnub/modules/crypto/crypto_module.rb +159 -0
  38. data/lib/pubnub/modules/crypto/crypto_provider.rb +31 -0
  39. data/lib/pubnub/modules/crypto/cryptor.rb +73 -0
  40. data/lib/pubnub/modules/crypto/cryptor_header.rb +251 -0
  41. data/lib/pubnub/modules/crypto/cryptors/aes_cbc_cryptor.rb +67 -0
  42. data/lib/pubnub/modules/crypto/cryptors/legacy_cryptor.rb +84 -0
  43. data/lib/pubnub/modules/crypto/module.rb +8 -0
  44. data/lib/pubnub/subscribe_event/formatter.rb +8 -8
  45. data/lib/pubnub/version.rb +1 -1
  46. data/pubnub.gemspec +2 -2
  47. metadata +16 -5
  48. data/LICENSE.txt +0 -30
  49. data/lib/pubnub/crypto.rb +0 -70
@@ -0,0 +1,251 @@
1
+ module Pubnub
2
+ module Crypto
3
+ # Cryptor data header.
4
+ #
5
+ # This instance used to parse header from received data and encode into
6
+ # binary for sending.
7
+ class CryptorHeader
8
+ module Versions
9
+ # Currently used cryptor data header schema version.
10
+ CURRENT_VERSION = 1
11
+
12
+ # Base class for cryptor data schema.
13
+ class CryptorHeaderData
14
+ # Cryptor header version.
15
+ #
16
+ # @return [Integer] Cryptor header version.
17
+ def version
18
+ raise NotImplementedError, 'Subclass should provide "version" method implementation.'
19
+ end
20
+
21
+ # Cryptor identifier.
22
+ #
23
+ # @return [String] Identifier of the cryptor which has been used to
24
+ # encrypt data.
25
+ def identifier
26
+ raise NotImplementedError, 'Subclass should provide "identifier" method implementation.'
27
+ end
28
+
29
+ # Cryptor-defined data size.
30
+ #
31
+ # @return [Integer] Cryptor-defined data size.
32
+ def data_size
33
+ raise NotImplementedError, 'Subclass should provide "data_size" method implementation.'
34
+ end
35
+ end
36
+
37
+ # v1 cryptor header schema.
38
+ #
39
+ # This header consists of:
40
+ # * sentinel (4 bytes)
41
+ # * version (1 byte)
42
+ # * cryptor identifier (4 bytes)
43
+ # * cryptor data size (1 byte if less than 255 and 3 bytes in other cases)
44
+ # * cryptor-defined data
45
+ class CryptorHeaderV1Data < CryptorHeaderData
46
+ # Identifier of the cryptor which has been used to encrypt data.
47
+ #
48
+ # @return [String] Identifier of the cryptor which has been used to
49
+ # encrypt data.
50
+ attr_reader :identifier
51
+
52
+ # Cryptor-defined data size.
53
+ #
54
+ # @return [Integer] Cryptor-defined data size.
55
+ attr_reader :data_size
56
+
57
+ # Create cryptor header data.
58
+ #
59
+ # @param identifier [String] Identifier of the cryptor which has been
60
+ # used to encrypt data.
61
+ # @param data_size [Integer] Cryptor-defined data size.
62
+ def initialize(identifier, data_size)
63
+ @identifier = identifier
64
+ @data_size = data_size
65
+ end
66
+
67
+ def version
68
+ 1
69
+ end
70
+ end
71
+ end
72
+
73
+ # Create cryptor header.
74
+ #
75
+ # @param identifier [String] Identifier of the cryptor which has been used
76
+ # to encrypt data.
77
+ # @param metadata [String, nil] Cryptor-defined information.
78
+ def initialize(identifier = nil, metadata = nil)
79
+ @data = if identifier && identifier != '\x00\x00\x00\x00'
80
+ Versions::CryptorHeaderV1Data.new(
81
+ identifier.to_s,
82
+ metadata&.length || 0
83
+ )
84
+ end
85
+ end
86
+
87
+ # Parse cryptor header data to create instance.
88
+ #
89
+ # @param data [String] Data which <i>may</i> contain cryptor header
90
+ # information.
91
+ # @return [CryptorHeader, nil] Header instance or <i>nil</i> in case of
92
+ # encrypted data parse error.
93
+ #
94
+ # @raise [ArgumentError] Raise an exception if <i>data</i> is <i>nil</i>
95
+ # or empty.
96
+ # @raise [UnknownCryptorError] Raise an exception if, during cryptor
97
+ # header data parsing, an unknown cryptor header version is encountered.
98
+ def self.parse(data)
99
+ if data.nil? || data.empty?
100
+ raise ArgumentError, {
101
+ message: '\'data\' is required and should not be empty.'
102
+ }
103
+ end
104
+
105
+ # Data is too short to be encrypted. Assume legacy cryptor without
106
+ # header.
107
+ return CryptorHeader.new if data.length < 4 || data.unpack('A4').last != 'PNED'
108
+
109
+ # Malformed crypto header.
110
+ return nil if data.length < 10
111
+
112
+ # Unpack header bytes.
113
+ _, version, identifier, data_size = data.unpack('A4 C A4 C')
114
+
115
+ # Check whether version is within known range.
116
+ if version > current_version
117
+ raise UnknownCryptorError, {
118
+ message: 'Decrypting data created by unknown cryptor.'
119
+ }
120
+ end
121
+
122
+ if data_size == 255
123
+ data_size = data.unpack('A4 C A4 C n').last if data.length >= 12
124
+ return CryptorHeader.new if data.length < 12
125
+ end
126
+
127
+ header = CryptorHeader.new
128
+ header.send(
129
+ :update_header_data,
130
+ create_header_data(version.to_i, identifier.to_s, data_size.to_i)
131
+ )
132
+ header
133
+ end
134
+
135
+ # Overall header size.
136
+ #
137
+ # Full header size which includes:
138
+ # * sentinel
139
+ # * version
140
+ # * cryptor identifier
141
+ # * cryptor data size
142
+ # * cryptor-defined fields size.
143
+ def length
144
+ # Legacy payload doesn't have header.
145
+ return 0 if @data.nil?
146
+
147
+ 9 + (data_size < 255 ? 1 : 3)
148
+ end
149
+
150
+ # Crypto header version Version module.
151
+ #
152
+ # @return [Integer] One of known versions from Version module.
153
+ def version
154
+ header_data&.version || 0
155
+ end
156
+
157
+ # Identifier of the cryptor which has been used to encrypt data.
158
+ #
159
+ # @return [String, nil] Identifier of the cryptor which has been used to
160
+ # encrypt data.
161
+ def identifier
162
+ header_data&.identifier || nil
163
+ end
164
+
165
+ # Cryptor-defined information size.
166
+ #
167
+ # @return [Integer] Cryptor-defined information size.
168
+ def data_size
169
+ header_data&.data_size || 0
170
+ end
171
+
172
+ # Create cryptor header data object.
173
+ #
174
+ # @param version [Integer] Cryptor header data schema version.
175
+ # @param identifier [String] Encrypting cryptor identifier.
176
+ # @param size [Integer] Cryptor-defined data size
177
+ # @return [Versions::CryptorHeaderData] Cryptor header data.
178
+ def self.create_header_data(version, identifier, size)
179
+ Versions::CryptorHeaderV1Data.new(identifier, size) if version == 1
180
+ end
181
+
182
+ # Crypto header which is currently used to encrypt data.
183
+ #
184
+ # @return [Integer] Current cryptor header version.
185
+ def self.current_version
186
+ Versions::CURRENT_VERSION
187
+ end
188
+
189
+ # Serialize cryptor header.
190
+ #
191
+ # @return [String] Cryptor header data, which is serialized as a binary
192
+ # string.
193
+ #
194
+ # @raise [ArgumentError] Raise an exception if a <i>cryptor</i> identifier
195
+ # is not provided for a non-legacy <i>cryptor</i>.
196
+ def to_s
197
+ # We don't need to serialize header for legacy cryptor.
198
+ return '' if version.zero?
199
+
200
+ cryptor_identifier = identifier
201
+ if cryptor_identifier.nil? || cryptor_identifier.empty?
202
+ raise ArgumentError, {
203
+ message: '\'identifier\' is missing or empty.'
204
+ }
205
+ end
206
+
207
+ header_bytes = ['PNED', version, cryptor_identifier]
208
+ if data_size < 255
209
+ header_bytes.push(data_size)
210
+ else
211
+ header_bytes.push(255, data_size)
212
+ end
213
+
214
+ header_bytes.pack(data_size < 255 ? 'A4 C A4 C' : 'A4 C A4 C n')
215
+ end
216
+
217
+ private
218
+
219
+ # Versioned cryptor header data
220
+ #
221
+ # @return [Versions::CryptorHeaderData, nil] Cryptor header data.
222
+ def header_data
223
+ @data
224
+ end
225
+
226
+ # Update crypto header version.
227
+ #
228
+ # @param data [Versions::CryptorHeaderData] Header version number parsed from binary data.
229
+ def update_header_data(data)
230
+ @data = data
231
+ end
232
+
233
+ # Update crypto header version.
234
+ #
235
+ # @param value [Integer] Header version number parsed from binary data.
236
+ def update_version(value)
237
+ @version = value
238
+ end
239
+
240
+ # Update cryptor-defined data size.
241
+ #
242
+ # @param value [Integer] Cryptor-defined data size parsed from binary
243
+ # data.
244
+ def update_data_size(value)
245
+ @data_size = value
246
+ end
247
+
248
+ private_class_method :create_header_data, :current_version
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubnub
4
+ module Crypto
5
+ # AES-256-CBC cryptor.
6
+ #
7
+ # The cryptor provides _encryption_ and _decryption_ using <i>AES-256</i> in
8
+ # <i>CBC</i> mode with a cipher key and random initialization vector.
9
+ # When it is registered as a secondary with other cryptors, it will provide
10
+ # backward compatibility with previously encrypted data.
11
+ class AesCbcCryptor < Cryptor
12
+ # AES-128 CBC block size.
13
+ BLOCK_SIZE = 16
14
+
15
+ # Create AES-256-CBC cryptor instance.
16
+ #
17
+ # @param cipher_key [String] Key for data <i>encryption</i> and
18
+ # <i>decryption</i>.
19
+ def initialize(cipher_key)
20
+ @cipher_key = Digest::SHA256.digest(cipher_key)
21
+ @alg = 'AES-256-CBC'
22
+ super()
23
+ end
24
+
25
+ def identifier
26
+ 'ACRH'
27
+ end
28
+
29
+ def encrypt(data)
30
+ if data.nil? || data.empty?
31
+ puts 'Pubnub :: ENCRYPTION ERROR: Empty data for encryption'
32
+ return nil
33
+ end
34
+
35
+ iv = OpenSSL::Random.random_bytes BLOCK_SIZE
36
+ cipher = OpenSSL::Cipher.new(@alg).encrypt
37
+ cipher.key = @cipher_key
38
+ cipher.iv = iv
39
+
40
+ encoded_message = cipher.update data
41
+ encoded_message << cipher.final
42
+ Crypto::EncryptedData.new(encoded_message, iv)
43
+ rescue StandardError => e
44
+ puts "Pubnub :: ENCRYPTION ERROR: #{e}"
45
+ nil
46
+ end
47
+
48
+ def decrypt(data)
49
+ if data.metadata.length != BLOCK_SIZE
50
+ puts "Pubnub :: DECRYPTION ERROR: Unexpected initialization vector length:
51
+ #{data.metadata.length} bytes (#{BLOCK_SIZE} bytes is expected)"
52
+ return nil
53
+ end
54
+
55
+ cipher = OpenSSL::Cipher.new(@alg).decrypt
56
+ cipher.key = @cipher_key
57
+ cipher.iv = data.metadata
58
+
59
+ decrypted = cipher.update data.data
60
+ decrypted << cipher.final
61
+ rescue StandardError => e
62
+ puts "Pubnub :: DECRYPTION ERROR: #{e}"
63
+ nil
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,84 @@
1
+ module Pubnub
2
+ module Crypto
3
+ # Legacy cryptor.
4
+ #
5
+ # The cryptor provides _encryption_ and _decryption_ using <i>`AES-256</i> in
6
+ # <i>CBC</i> mode with a cipher key and configurable initialization vector
7
+ # randomness.
8
+ # When it is registered as a secondary with other cryptors, it will provide
9
+ # backward compatibility with previously encrypted data.
10
+ #
11
+ # <b>Important</b>: It has been reported that the digest from cipherKey has
12
+ # low entropy, and it is suggested to use <i>AesCbcCryptor</i> instead.
13
+ class LegacyCryptor < Cryptor
14
+ # AES-128 CBC block size.
15
+ BLOCK_SIZE = 16
16
+
17
+ # Create legacy cryptor instance.
18
+ #
19
+ # @param cipher_key [String] Key for data <i>encryption</i> and
20
+ # <i>decryption</i>.
21
+ # @param use_random_iv [Boolean] Whether random IV should be used.
22
+ def initialize(cipher_key, use_random_iv = true)
23
+ @alg = 'AES-256-CBC'
24
+ @original_cipher_key = cipher_key
25
+ @cipher_key = Digest::SHA256.hexdigest(cipher_key.to_s).slice(0, 32)
26
+ @iv = use_random_iv ? nil : '0123456789012345'
27
+ super()
28
+ end
29
+
30
+ def identifier
31
+ '\x00\x00\x00\x00'
32
+ end
33
+
34
+ def encrypt(data)
35
+ if data.nil? || data.empty?
36
+ puts 'Pubnub :: ENCRYPTION ERROR: Empty data for encryption'
37
+ return nil
38
+ end
39
+
40
+ iv = @iv || OpenSSL::Random.random_bytes(BLOCK_SIZE)
41
+ cipher = OpenSSL::Cipher.new(@alg).encrypt
42
+ cipher.key = @cipher_key
43
+ cipher.iv = iv
44
+
45
+ encoded_message = ''
46
+ encoded_message << iv if @iv.nil? && iv
47
+ encoded_message << cipher.update(data)
48
+ encoded_message << cipher.final
49
+ Crypto::EncryptedData.new(encoded_message)
50
+ rescue StandardError => e
51
+ puts "Pubnub :: ENCRYPTION ERROR: #{e}"
52
+ nil
53
+ end
54
+
55
+ def decrypt(data)
56
+ encrypted_data = data.data
57
+ iv = if @iv.nil? && encrypted_data.length >= BLOCK_SIZE
58
+ encrypted_data.slice!(0..(BLOCK_SIZE - 1)) if encrypted_data.length >= BLOCK_SIZE
59
+ else
60
+ @iv
61
+ end
62
+ if iv.length != BLOCK_SIZE
63
+ puts "Pubnub :: DECRYPTION ERROR: Unexpected initialization vector length: #{data.metadata.length} bytes (#{BLOCK_SIZE} bytes is expected)"
64
+ return nil
65
+ end
66
+
67
+ unless encrypted_data.length.positive?
68
+ puts 'Pubnub :: DECRYPTION ERROR: Empty data for decryption'
69
+ return nil
70
+ end
71
+
72
+ cipher = OpenSSL::Cipher.new(@alg).decrypt
73
+ cipher.key = @cipher_key
74
+ cipher.iv = iv
75
+
76
+ decrypted = cipher.update encrypted_data
77
+ decrypted << cipher.final
78
+ rescue StandardError => e
79
+ puts "Pubnub :: DECRYPTION ERROR: #{e}"
80
+ nil
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pubnub/modules/crypto/cryptor'
4
+ require 'pubnub/modules/crypto/cryptors/aes_cbc_cryptor'
5
+ require 'pubnub/modules/crypto/cryptors/legacy_cryptor'
6
+ require 'pubnub/modules/crypto/crypto_provider'
7
+ require 'pubnub/modules/crypto/cryptor_header'
8
+ require 'pubnub/modules/crypto/crypto_module'
@@ -33,13 +33,12 @@ module Pubnub
33
33
  end
34
34
 
35
35
  def decipher_payload(message)
36
- return message[:payload] if message[:channel].end_with?('-pnpres') || (@app.env[:cipher_key].nil? && @cipher_key.nil? && @cipher_key_selector.nil? && @env[:cipher_key_selector].nil?)
37
- data = message.reject { |k, _v| k == :payload }
38
- cipher_key = compute_cipher_key(data)
39
- random_iv = compute_random_iv(data)
40
- crypto = Pubnub::Crypto.new(cipher_key, random_iv)
41
- JSON.parse(crypto.decrypt(message[:payload]), quirks_mode: true)
42
- rescue StandardError
36
+ # TODO: Uncomment code below when cryptor implementations will be added.
37
+ return message[:payload] if message[:channel].end_with?('-pnpres') || crypto_module.nil?
38
+
39
+ encrypted_message = Base64.decode64(message[:payload])
40
+ JSON.parse(crypto_module.decrypt(encrypted_message), quirks_mode: true)
41
+ rescue StandardError, UnknownCryptorError
43
42
  message[:payload]
44
43
  end
45
44
 
@@ -51,7 +50,8 @@ module Pubnub
51
50
  # STATUS
52
51
  envelopes = if messages.empty?
53
52
  [plain_envelope(req_res_objects, timetoken)]
54
- else # RESULT
53
+ else
54
+ # RESULT
55
55
  messages.map do |message|
56
56
  encrypted_envelope(req_res_objects, message, timetoken)
57
57
  end
@@ -1,4 +1,4 @@
1
1
  # Toplevel Pubnub module.
2
2
  module Pubnub
3
- VERSION = '5.2.1'.freeze
3
+ VERSION = '5.3.0'.freeze
4
4
  end
data/pubnub.gemspec CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ['support@pubnub.com']
10
10
  spec.summary = 'PubNub Official Ruby gem.'
11
11
  spec.description = 'Ruby anywhere in the world in 250ms with PubNub!'
12
- spec.homepage = 'http://github.com/pubnub/ruby'
13
- spec.license = 'MIT'
12
+ spec.homepage = 'https://github.com/pubnub/ruby'
13
+ spec.licenses = %w[MIT LicenseRef-LICENSE]
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0").grep_v(/^(test|spec|fixtures)/)
16
16
  spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pubnub
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.1
4
+ version: 5.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - PubNub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-13 00:00:00.000000000 Z
11
+ date: 2023-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -143,7 +143,7 @@ files:
143
143
  - CHANGELOG.md
144
144
  - Gemfile
145
145
  - Gemfile.lock
146
- - LICENSE.txt
146
+ - LICENSE
147
147
  - Pubnub Ruby SDK upgrade guide.md
148
148
  - README.md
149
149
  - Rakefile
@@ -151,6 +151,8 @@ files:
151
151
  - config/cucumber.yml
152
152
  - docs.md
153
153
  - features/step_definitions/access_steps.rb
154
+ - features/step_definitions/crypto_steps.rb
155
+ - features/support/cryptor.rb
154
156
  - features/support/env.rb
155
157
  - features/support/helper.rb
156
158
  - features/support/hooks.rb
@@ -171,7 +173,6 @@ files:
171
173
  - lib/pubnub/client/paged_history.rb
172
174
  - lib/pubnub/configuration.rb
173
175
  - lib/pubnub/constants.rb
174
- - lib/pubnub/crypto.rb
175
176
  - lib/pubnub/envelope.rb
176
177
  - lib/pubnub/error.rb
177
178
  - lib/pubnub/error_envelope.rb
@@ -222,6 +223,13 @@ files:
222
223
  - lib/pubnub/format.rb
223
224
  - lib/pubnub/formatter.rb
224
225
  - lib/pubnub/heart.rb
226
+ - lib/pubnub/modules/crypto/crypto_module.rb
227
+ - lib/pubnub/modules/crypto/crypto_provider.rb
228
+ - lib/pubnub/modules/crypto/cryptor.rb
229
+ - lib/pubnub/modules/crypto/cryptor_header.rb
230
+ - lib/pubnub/modules/crypto/cryptors/aes_cbc_cryptor.rb
231
+ - lib/pubnub/modules/crypto/cryptors/legacy_cryptor.rb
232
+ - lib/pubnub/modules/crypto/module.rb
225
233
  - lib/pubnub/origin_manager.rb
226
234
  - lib/pubnub/pam.rb
227
235
  - lib/pubnub/schemas/envelope_schema.rb
@@ -281,9 +289,10 @@ files:
281
289
  - lib/pubnub/validators/where_now.rb
282
290
  - lib/pubnub/version.rb
283
291
  - pubnub.gemspec
284
- homepage: http://github.com/pubnub/ruby
292
+ homepage: https://github.com/pubnub/ruby
285
293
  licenses:
286
294
  - MIT
295
+ - LicenseRef-LICENSE
287
296
  metadata: {}
288
297
  post_install_message:
289
298
  rdoc_options: []
@@ -306,6 +315,8 @@ specification_version: 4
306
315
  summary: PubNub Official Ruby gem.
307
316
  test_files:
308
317
  - features/step_definitions/access_steps.rb
318
+ - features/step_definitions/crypto_steps.rb
319
+ - features/support/cryptor.rb
309
320
  - features/support/env.rb
310
321
  - features/support/helper.rb
311
322
  - features/support/hooks.rb
data/LICENSE.txt DELETED
@@ -1,30 +0,0 @@
1
- PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks
2
- Copyright (c) 2013-2014 PubNub Inc.
3
- http://www.pubnub.com/
4
- http://www.pubnub.com/terms
5
-
6
- MIT License
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining
9
- a copy of this software and associated documentation files (the
10
- "Software"), to deal in the Software without restriction, including
11
- without limitation the rights to use, copy, modify, merge, publish,
12
- distribute, sublicense, and/or sell copies of the Software, and to
13
- permit persons to whom the Software is furnished to do so, subject to
14
- the following conditions:
15
-
16
- The above copyright notice and this permission notice shall be
17
- included in all copies or substantial portions of the Software.
18
-
19
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
-
27
- PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks
28
- Copyright (c) 2013-2014 PubNub Inc.
29
- http://www.pubnub.com/
30
- http://www.pubnub.com/terms
data/lib/pubnub/crypto.rb DELETED
@@ -1,70 +0,0 @@
1
- # Toplevel Pubnub module.
2
- module Pubnub
3
- # Internal Crypto class used for message encryption and decryption
4
- class Crypto
5
- def initialize(cipher_key, use_random_iv)
6
- @alg = 'AES-256-CBC'
7
- sha256_key = Digest::SHA256.hexdigest(cipher_key.to_s)
8
- @key = sha256_key.slice(0, 32)
9
- @using_random_iv = use_random_iv
10
- @iv = @using_random_iv == true ? random_iv : '0123456789012345'
11
- end
12
-
13
- def encrypt(message)
14
- aes = OpenSSL::Cipher.new(@alg)
15
- aes.encrypt
16
- aes.key = @key
17
- aes.iv = @iv
18
-
19
- json_message = message.to_json
20
- cipher = @using_random_iv == true ? @iv : ''
21
- cipher << aes.update(json_message)
22
- cipher << aes.final
23
-
24
- Base64.strict_encode64(cipher)
25
- end
26
-
27
- def decrypt(cipher_text)
28
- undecoded_text = Base64.decode64(cipher_text)
29
- iv = @iv
30
-
31
- if cipher_text.length > 16 && @using_random_iv == true
32
- iv = undecoded_text.slice!(0..15)
33
- end
34
-
35
- decode_cipher = OpenSSL::Cipher.new(@alg).decrypt
36
- decode_cipher.key = @key
37
- decode_cipher.iv = iv
38
-
39
- plain_text = decryption(undecoded_text, decode_cipher)
40
- load_json(plain_text)
41
-
42
- Pubnub.logger.debug('Pubnub') { 'Finished decrypting' }
43
-
44
- plain_text
45
- end
46
-
47
- private
48
-
49
- def decryption(cipher_text, decode_cipher)
50
- plain_text = decode_cipher.update(cipher_text)
51
- plain_text << decode_cipher.final
52
- rescue StandardError => e
53
- Pubnub.error('Pubnub') { "DECRYPTION ERROR #{e}" }
54
- '"DECRYPTION ERROR"'
55
- end
56
-
57
- def load_json(plain_text)
58
- JSON.load(plain_text)
59
- rescue JSON::ParserError
60
- JSON.load("[#{plain_text}]")[0]
61
- end
62
-
63
- private
64
-
65
- def random_iv
66
- random_bytes = Random.new.bytes(16).unpack('NnnnnN')
67
- format('%08x%04x%04x', *random_bytes)
68
- end
69
- end
70
- end