pubnub 5.2.1 → 5.3.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.
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