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.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +2 -2
- data/.github/workflows/commands-handler.yml +18 -2
- data/.github/workflows/run-tests.yml +27 -17
- data/.github/workflows/run-validations.yml +12 -2
- data/.pubnub.yml +20 -4
- data/.tool-versions +1 -1
- data/CHANGELOG.md +15 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +6 -6
- data/LICENSE +29 -0
- data/README.md +1 -1
- data/VERSION +1 -1
- data/features/step_definitions/access_steps.rb +0 -2
- data/features/step_definitions/crypto_steps.rb +99 -0
- data/features/support/cryptor.rb +58 -0
- data/features/support/hooks.rb +0 -1
- data/lib/pubnub/client.rb +30 -1
- data/lib/pubnub/error.rb +3 -0
- data/lib/pubnub/event.rb +13 -5
- data/lib/pubnub/events/add_message_action.rb +2 -2
- data/lib/pubnub/events/get_message_actions.rb +1 -1
- data/lib/pubnub/events/grant_token.rb +1 -1
- data/lib/pubnub/events/history.rb +18 -6
- data/lib/pubnub/events/publish.rb +7 -3
- data/lib/pubnub/events/remove_channel_members.rb +3 -3
- data/lib/pubnub/events/remove_channel_metadata.rb +1 -1
- data/lib/pubnub/events/remove_memberships.rb +3 -3
- data/lib/pubnub/events/remove_uuid_metadata.rb +1 -1
- data/lib/pubnub/events/set_channel_members.rb +3 -3
- data/lib/pubnub/events/set_channel_metadata.rb +2 -2
- data/lib/pubnub/events/set_memberships.rb +3 -3
- data/lib/pubnub/events/set_uuid_metadata.rb +2 -2
- data/lib/pubnub/events/signal.rb +1 -1
- data/lib/pubnub/events/subscribe.rb +5 -0
- data/lib/pubnub/formatter.rb +22 -11
- data/lib/pubnub/modules/crypto/crypto_module.rb +159 -0
- data/lib/pubnub/modules/crypto/crypto_provider.rb +31 -0
- data/lib/pubnub/modules/crypto/cryptor.rb +73 -0
- data/lib/pubnub/modules/crypto/cryptor_header.rb +251 -0
- data/lib/pubnub/modules/crypto/cryptors/aes_cbc_cryptor.rb +67 -0
- data/lib/pubnub/modules/crypto/cryptors/legacy_cryptor.rb +84 -0
- data/lib/pubnub/modules/crypto/module.rb +8 -0
- data/lib/pubnub/subscribe_event/formatter.rb +8 -8
- data/lib/pubnub/version.rb +1 -1
- data/pubnub.gemspec +2 -2
- metadata +16 -5
- data/LICENSE.txt +0 -30
- 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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
53
|
+
else
|
54
|
+
# RESULT
|
55
55
|
messages.map do |message|
|
56
56
|
encrypted_envelope(req_res_objects, message, timetoken)
|
57
57
|
end
|
data/lib/pubnub/version.rb
CHANGED
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 = '
|
13
|
-
spec.
|
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.
|
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:
|
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
|
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:
|
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
|