pubnub 5.2.2 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -2
  3. data/.pubnub.yml +11 -4
  4. data/.tool-versions +1 -1
  5. data/CHANGELOG.md +9 -0
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +6 -6
  8. data/LICENSE +29 -0
  9. data/VERSION +1 -1
  10. data/features/step_definitions/access_steps.rb +0 -2
  11. data/features/step_definitions/crypto_steps.rb +99 -0
  12. data/features/support/cryptor.rb +58 -0
  13. data/features/support/hooks.rb +0 -1
  14. data/lib/pubnub/client.rb +30 -1
  15. data/lib/pubnub/error.rb +3 -0
  16. data/lib/pubnub/event.rb +13 -5
  17. data/lib/pubnub/events/add_message_action.rb +2 -2
  18. data/lib/pubnub/events/grant_token.rb +1 -1
  19. data/lib/pubnub/events/history.rb +18 -6
  20. data/lib/pubnub/events/publish.rb +7 -3
  21. data/lib/pubnub/events/remove_channel_members.rb +3 -3
  22. data/lib/pubnub/events/remove_channel_metadata.rb +1 -1
  23. data/lib/pubnub/events/remove_memberships.rb +3 -3
  24. data/lib/pubnub/events/remove_uuid_metadata.rb +1 -1
  25. data/lib/pubnub/events/set_channel_members.rb +3 -3
  26. data/lib/pubnub/events/set_channel_metadata.rb +2 -2
  27. data/lib/pubnub/events/set_memberships.rb +3 -3
  28. data/lib/pubnub/events/set_uuid_metadata.rb +2 -2
  29. data/lib/pubnub/events/signal.rb +1 -1
  30. data/lib/pubnub/events/subscribe.rb +5 -0
  31. data/lib/pubnub/formatter.rb +22 -11
  32. data/lib/pubnub/modules/crypto/crypto_module.rb +159 -0
  33. data/lib/pubnub/modules/crypto/crypto_provider.rb +31 -0
  34. data/lib/pubnub/modules/crypto/cryptor.rb +73 -0
  35. data/lib/pubnub/modules/crypto/cryptor_header.rb +251 -0
  36. data/lib/pubnub/modules/crypto/cryptors/aes_cbc_cryptor.rb +67 -0
  37. data/lib/pubnub/modules/crypto/cryptors/legacy_cryptor.rb +84 -0
  38. data/lib/pubnub/modules/crypto/module.rb +8 -0
  39. data/lib/pubnub/subscribe_event/formatter.rb +8 -8
  40. data/lib/pubnub/version.rb +1 -1
  41. data/pubnub.gemspec +2 -2
  42. metadata +16 -5
  43. data/LICENSE.txt +0 -30
  44. data/lib/pubnub/crypto.rb +0 -70
@@ -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.2'.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.2
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: 2023-03-15 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