ably 0.8.8 → 0.8.9
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/CHANGELOG.md +16 -2
- data/LICENSE +2 -2
- data/README.md +81 -20
- data/SPEC.md +235 -178
- data/lib/ably/auth.rb +1 -1
- data/lib/ably/exceptions.rb +10 -1
- data/lib/ably/models/cipher_params.rb +114 -0
- data/lib/ably/models/connection_details.rb +8 -6
- data/lib/ably/models/error_info.rb +3 -3
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +27 -20
- data/lib/ably/models/message.rb +15 -15
- data/lib/ably/models/message_encoders/cipher.rb +8 -7
- data/lib/ably/models/presence_message.rb +17 -17
- data/lib/ably/models/protocol_message.rb +26 -19
- data/lib/ably/models/stats.rb +15 -15
- data/lib/ably/models/token_details.rb +14 -12
- data/lib/ably/models/token_request.rb +16 -14
- data/lib/ably/modules/async_wrapper.rb +1 -1
- data/lib/ably/modules/encodeable.rb +10 -10
- data/lib/ably/modules/model_common.rb +13 -5
- data/lib/ably/realtime/channel.rb +1 -2
- data/lib/ably/realtime/presence.rb +29 -58
- data/lib/ably/realtime/presence/members_map.rb +2 -2
- data/lib/ably/rest/channel.rb +1 -2
- data/lib/ably/rest/middleware/exceptions.rb +14 -4
- data/lib/ably/rest/presence.rb +3 -1
- data/lib/ably/util/crypto.rb +50 -40
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/message_spec.rb +20 -20
- data/spec/acceptance/realtime/presence_history_spec.rb +7 -7
- data/spec/acceptance/realtime/presence_spec.rb +65 -77
- data/spec/acceptance/rest/auth_spec.rb +8 -8
- data/spec/acceptance/rest/base_spec.rb +4 -4
- data/spec/acceptance/rest/channel_spec.rb +1 -1
- data/spec/acceptance/rest/client_spec.rb +1 -1
- data/spec/acceptance/rest/encoders_spec.rb +4 -4
- data/spec/acceptance/rest/message_spec.rb +15 -15
- data/spec/acceptance/rest/presence_spec.rb +4 -4
- data/spec/shared/model_behaviour.rb +7 -7
- data/spec/unit/models/cipher_params_spec.rb +140 -0
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +15 -8
- data/spec/unit/models/message_encoders/cipher_spec.rb +28 -22
- data/spec/unit/models/message_encoders/json_spec.rb +24 -0
- data/spec/unit/models/protocol_message_spec.rb +3 -3
- data/spec/unit/util/crypto_spec.rb +50 -17
- metadata +5 -2
@@ -18,7 +18,7 @@ describe Ably::Auth do
|
|
18
18
|
:client_id,
|
19
19
|
:timestamp,
|
20
20
|
:nonce
|
21
|
-
].map { |key| "#{token_request.
|
21
|
+
].map { |key| "#{token_request.attributes[key]}\n" }.join("")
|
22
22
|
|
23
23
|
encode64(
|
24
24
|
OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, secret, text)
|
@@ -702,7 +702,7 @@ describe Ably::Auth do
|
|
702
702
|
|
703
703
|
it 'calls the Proc once the token has expired and the new token is used' do
|
704
704
|
client.stats
|
705
|
-
expect(@block_called).to
|
705
|
+
expect(@block_called).to eql(0)
|
706
706
|
sleep 3.5
|
707
707
|
expect { client.stats }.to change { client.auth.current_token_details }
|
708
708
|
expect(@block_called).to eql(1)
|
@@ -824,9 +824,9 @@ describe Ably::Auth do
|
|
824
824
|
context 'with additional invalid attributes' do
|
825
825
|
let(:token_params) { { nonce: 'valid', is_not_used_by_token_request: 'invalid' } }
|
826
826
|
specify 'are ignored' do
|
827
|
-
expect(subject.
|
828
|
-
expect(subject.
|
829
|
-
expect(subject.
|
827
|
+
expect(subject.attributes.keys).to_not include(:is_not_used_by_token_request)
|
828
|
+
expect(subject.attributes.keys).to_not include(convert_to_mixed_case(:is_not_used_by_token_request))
|
829
|
+
expect(subject.attributes.keys).to include(:nonce)
|
830
830
|
expect(subject.nonce).to eql('valid')
|
831
831
|
end
|
832
832
|
end
|
@@ -890,7 +890,7 @@ describe Ably::Auth do
|
|
890
890
|
end
|
891
891
|
|
892
892
|
it 'generates a valid HMAC' do
|
893
|
-
hmac = hmac_for(Ably::Models::TokenRequest(token_request_attributes).
|
893
|
+
hmac = hmac_for(Ably::Models::TokenRequest(token_request_attributes).attributes, key_secret)
|
894
894
|
expect(subject['mac']).to eql(hmac)
|
895
895
|
end
|
896
896
|
end
|
@@ -918,7 +918,7 @@ describe Ably::Auth do
|
|
918
918
|
|
919
919
|
it 'disallows publishing on unspecified capability channels' do
|
920
920
|
expect { token_auth_client.channel('bar').publish('event', 'data') }.to raise_error do |error|
|
921
|
-
expect(error).to be_a(Ably::Exceptions::
|
921
|
+
expect(error).to be_a(Ably::Exceptions::UnauthorizedRequest)
|
922
922
|
expect(error.status).to eql(401)
|
923
923
|
expect(error.code).to eql(40160)
|
924
924
|
end
|
@@ -926,7 +926,7 @@ describe Ably::Auth do
|
|
926
926
|
|
927
927
|
it 'fails if timestamp is invalid' do
|
928
928
|
expect { auth.request_token(timestamp: Time.now - 180) }.to raise_error do |error|
|
929
|
-
expect(error).to be_a(Ably::Exceptions::
|
929
|
+
expect(error).to be_a(Ably::Exceptions::UnauthorizedRequest)
|
930
930
|
expect(error.status).to eql(401)
|
931
931
|
expect(error.code).to eql(40101)
|
932
932
|
end
|
@@ -75,10 +75,10 @@ describe Ably::Rest do
|
|
75
75
|
it 'should raise an InvalidRequest exception with a valid error message and code' do
|
76
76
|
invalid_client = Ably::Rest::Client.new(key: 'appid.keyuid:keysecret', environment: environment)
|
77
77
|
expect { invalid_client.channel('test').publish('foo', 'choo') }.to raise_error do |error|
|
78
|
-
expect(error).to be_a(Ably::Exceptions::
|
79
|
-
expect(error.message).to match(/
|
80
|
-
expect(error.code).to eql(
|
81
|
-
expect(error.status).to eql(
|
78
|
+
expect(error).to be_a(Ably::Exceptions::ResourceMissing)
|
79
|
+
expect(error.message).to match(/No application found/)
|
80
|
+
expect(error.code).to eql(40400)
|
81
|
+
expect(error.status).to eql(404)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
@@ -87,7 +87,7 @@ describe Ably::Rest::Channel do
|
|
87
87
|
let(:client_options) { default_options.merge(use_token_auth: true, token_params: { capability: capability }) }
|
88
88
|
|
89
89
|
it 'raises a permission error when publishing' do
|
90
|
-
expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::
|
90
|
+
expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::UnauthorizedRequest, /not permitted/)
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -382,7 +382,7 @@ describe Ably::Rest::Client do
|
|
382
382
|
end
|
383
383
|
|
384
384
|
it 'does not attempt the fallback hosts as this is an authentication failure' do
|
385
|
-
expect { publish_block.call }.to raise_error(Ably::Exceptions::
|
385
|
+
expect { publish_block.call }.to raise_error(Ably::Exceptions::UnauthorizedRequest)
|
386
386
|
expect(default_host_request_stub).to have_been_requested
|
387
387
|
expect(first_fallback_request_stub).to_not have_been_requested
|
388
388
|
expect(second_fallback_request_stub).to_not have_been_requested
|
@@ -9,12 +9,12 @@ describe Ably::Models::MessageEncoders do
|
|
9
9
|
let(:channel) { client.channel('test', channel_options) }
|
10
10
|
let(:response) { instance_double('Faraday::Response', status: 201) }
|
11
11
|
|
12
|
-
let(:cipher_params) { { key:
|
12
|
+
let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
13
13
|
let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
|
14
14
|
|
15
15
|
let(:utf_8_data) { random_str.encode(Encoding::UTF_8) }
|
16
16
|
let(:binary_data) { MessagePack.pack(random_str).encode(Encoding::ASCII_8BIT) }
|
17
|
-
let(:json_data) { { '
|
17
|
+
let(:json_data) { { 'some_id' => random_str } }
|
18
18
|
|
19
19
|
after do
|
20
20
|
channel.publish 'event', published_data
|
@@ -70,7 +70,7 @@ describe Ably::Models::MessageEncoders do
|
|
70
70
|
end
|
71
71
|
|
72
72
|
context 'with encryption' do
|
73
|
-
let(:channel_options) { {
|
73
|
+
let(:channel_options) { { cipher: cipher_params } }
|
74
74
|
|
75
75
|
context 'with UTF-8 data' do
|
76
76
|
let(:published_data) { utf_8_data }
|
@@ -146,7 +146,7 @@ describe Ably::Models::MessageEncoders do
|
|
146
146
|
end
|
147
147
|
|
148
148
|
context 'with encryption' do
|
149
|
-
let(:channel_options) { {
|
149
|
+
let(:channel_options) { { cipher: cipher_params } }
|
150
150
|
|
151
151
|
context 'with UTF-8 data' do
|
152
152
|
let(:published_data) { utf_8_data }
|
@@ -97,8 +97,8 @@ describe Ably::Rest::Channel, 'messages' do
|
|
97
97
|
|
98
98
|
describe 'encryption and encoding' do
|
99
99
|
let(:channel_name) { "persisted:#{random_str}" }
|
100
|
-
let(:
|
101
|
-
let(:
|
100
|
+
let(:encrypted_channel) { client.channel(channel_name, cipher: cipher_options) }
|
101
|
+
let(:cipher_options) { { key: Ably::Util::Crypto.generate_random_key } }
|
102
102
|
|
103
103
|
context 'with #publish and #history' do
|
104
104
|
shared_examples 'an Ably encrypter and decrypter' do |item, data|
|
@@ -108,7 +108,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
108
108
|
let(:secret_key) { Base64.decode64(data['key']) }
|
109
109
|
let(:iv) { Base64.decode64(data['iv']) }
|
110
110
|
|
111
|
-
let(:cipher_options) { { key: secret_key,
|
111
|
+
let(:cipher_options) { { key: secret_key, fixed_iv: iv, algorithm: algorithm, mode: mode, key_length: key_length } }
|
112
112
|
|
113
113
|
let(:encoded) { item['encoded'] }
|
114
114
|
let(:encoded_data) { encoded['data'] }
|
@@ -200,7 +200,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
200
200
|
context 'when retrieving #history with a different protocol' do
|
201
201
|
let(:other_protocol) { protocol == :msgpack ? :json : :msgpack }
|
202
202
|
let(:other_client) { Ably::Rest::Client.new(default_client_options.merge(protocol: other_protocol)) }
|
203
|
-
let(:other_client_channel) {
|
203
|
+
let(:other_client_channel) { other_client.channel(channel_name, cipher: cipher_options) }
|
204
204
|
|
205
205
|
before do
|
206
206
|
expect(other_client.protocol_binary?).to_not eql(client.protocol_binary?)
|
@@ -221,7 +221,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
221
221
|
|
222
222
|
context 'when publishing on an unencrypted channel and retrieving with #history on an encrypted channel' do
|
223
223
|
let(:unencrypted_channel) { client.channel(channel_name) }
|
224
|
-
let(:other_client_encrypted_channel) { other_client.channel(channel_name,
|
224
|
+
let(:other_client_encrypted_channel) { other_client.channel(channel_name, cipher: cipher_options) }
|
225
225
|
|
226
226
|
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
227
227
|
|
@@ -236,8 +236,8 @@ describe Ably::Rest::Channel, 'messages' do
|
|
236
236
|
|
237
237
|
context 'when publishing on an encrypted channel and retrieving with #history on an unencrypted channel' do
|
238
238
|
let(:client_options) { default_client_options.merge(log_level: :fatal) }
|
239
|
-
let(:cipher_options) { { key:
|
240
|
-
let(:encrypted_channel) { client.channel(channel_name,
|
239
|
+
let(:cipher_options) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
240
|
+
let(:encrypted_channel) { client.channel(channel_name, cipher: cipher_options) }
|
241
241
|
let(:other_client_unencrypted_channel) { other_client.channel(channel_name) }
|
242
242
|
|
243
243
|
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
@@ -262,10 +262,10 @@ describe Ably::Rest::Channel, 'messages' do
|
|
262
262
|
|
263
263
|
context 'publishing on an encrypted channel and retrieving #history with a different algorithm on another client' do
|
264
264
|
let(:client_options) { default_client_options.merge(log_level: :fatal) }
|
265
|
-
let(:cipher_options_client1) { { key:
|
266
|
-
let(:encrypted_channel_client1) { client.channel(channel_name,
|
267
|
-
let(:cipher_options_client2) { { key:
|
268
|
-
let(:encrypted_channel_client2) { other_client.channel(channel_name,
|
265
|
+
let(:cipher_options_client1) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
266
|
+
let(:encrypted_channel_client1) { client.channel(channel_name, cipher: cipher_options_client1) }
|
267
|
+
let(:cipher_options_client2) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
268
|
+
let(:encrypted_channel_client2) { other_client.channel(channel_name, cipher: cipher_options_client2) }
|
269
269
|
|
270
270
|
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
271
271
|
|
@@ -289,10 +289,10 @@ describe Ably::Rest::Channel, 'messages' do
|
|
289
289
|
|
290
290
|
context 'publishing on an encrypted channel and subscribing with a different key on another client' do
|
291
291
|
let(:client_options) { default_client_options.merge(log_level: :fatal) }
|
292
|
-
let(:cipher_options_client1) { { key:
|
293
|
-
let(:encrypted_channel_client1) { client.channel(channel_name,
|
294
|
-
let(:cipher_options_client2) { { key:
|
295
|
-
let(:encrypted_channel_client2) { other_client.channel(channel_name,
|
292
|
+
let(:cipher_options_client1) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
293
|
+
let(:encrypted_channel_client1) { client.channel(channel_name, cipher: cipher_options_client1) }
|
294
|
+
let(:cipher_options_client2) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
295
|
+
let(:encrypted_channel_client2) { other_client.channel(channel_name, cipher: cipher_options_client2) }
|
296
296
|
|
297
297
|
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
298
298
|
|
@@ -26,8 +26,8 @@ describe Ably::Rest::Presence do
|
|
26
26
|
let(:secret_key) { Base64.decode64(cipher_details.fetch('key')) }
|
27
27
|
let(:iv) { Base64.decode64(cipher_details.fetch('iv')) }
|
28
28
|
|
29
|
-
let(:cipher_options) { { key: secret_key, algorithm: algorithm, mode: mode, key_length: key_length,
|
30
|
-
let(:fixtures_channel) { client.channel('persisted:presence_fixtures',
|
29
|
+
let(:cipher_options) { { key: secret_key, algorithm: algorithm, mode: mode, key_length: key_length, fixed_iv: iv } }
|
30
|
+
let(:fixtures_channel) { client.channel('persisted:presence_fixtures', cipher: cipher_options, fixed_iv: iv) }
|
31
31
|
|
32
32
|
context 'tested against presence fixture data set up in test app' do
|
33
33
|
before(:context) do
|
@@ -321,8 +321,8 @@ describe Ably::Rest::Presence do
|
|
321
321
|
|
322
322
|
let(:data) { random_str(32) }
|
323
323
|
let(:channel_name) { "persisted:#{random_str(4)}" }
|
324
|
-
let(:cipher_options) { { key:
|
325
|
-
let(:presence) { client.channel(channel_name,
|
324
|
+
let(:cipher_options) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
325
|
+
let(:presence) { client.channel(channel_name, cipher: cipher_options).presence }
|
326
326
|
|
327
327
|
let(:crypto) { Ably::Util::Crypto.new(cipher_options) }
|
328
328
|
|
@@ -18,18 +18,18 @@ shared_examples 'a model' do |shared_options = {}|
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
context '#
|
21
|
+
context '#attributes', :api_private do
|
22
22
|
let(:model_options) { { action: 5 } }
|
23
23
|
|
24
|
-
it 'provides access to #
|
25
|
-
expect(model.
|
24
|
+
it 'provides access to #attributes' do
|
25
|
+
expect(model.attributes).to eq(model_options)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
context '#[]', :api_private do
|
30
30
|
let(:model_options) { { unusual: 'attribute' } }
|
31
31
|
|
32
|
-
it 'provides accessor method to #
|
32
|
+
it 'provides accessor method to #attributes' do
|
33
33
|
expect(model[:unusual]).to eql('attribute')
|
34
34
|
end
|
35
35
|
end
|
@@ -74,13 +74,13 @@ shared_examples 'a model' do |shared_options = {}|
|
|
74
74
|
let(:model_options) { { channel: 'name' } }
|
75
75
|
|
76
76
|
it 'prevents changes' do
|
77
|
-
expect { model.
|
77
|
+
expect { model.attributes[:channel] = 'new' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
|
78
78
|
end
|
79
79
|
|
80
80
|
it 'dups options' do
|
81
|
-
expect(model.
|
81
|
+
expect(model.attributes[:channel]).to eql('name')
|
82
82
|
model_options[:channel] = 'new'
|
83
|
-
expect(model.
|
83
|
+
expect(model.attributes[:channel]).to eql('name')
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
describe Ably::Models::CipherParams do
|
5
|
+
context ':key missing from constructor' do
|
6
|
+
subject { Ably::Models::CipherParams.new }
|
7
|
+
|
8
|
+
it 'raises an exception' do
|
9
|
+
expect { subject }.to raise_error(/key.*required/)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#key' do
|
14
|
+
context 'with :key in constructor' do
|
15
|
+
subject { Ably::Models::CipherParams.new(key: key) }
|
16
|
+
|
17
|
+
context 'as nil' do
|
18
|
+
let(:key) { nil }
|
19
|
+
|
20
|
+
it 'raises an exception' do
|
21
|
+
expect { subject }.to raise_error(/key.*required/)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'as a base64 encoded string' do
|
26
|
+
let(:binary_key) { Ably::Util::Crypto.generate_random_key }
|
27
|
+
let(:key) { Base64.encode64(binary_key) }
|
28
|
+
|
29
|
+
it 'is a binary representation of the base64 encoded string' do
|
30
|
+
expect(subject.key).to eql(binary_key)
|
31
|
+
expect(subject.key.encoding).to eql(Encoding::ASCII_8BIT)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'as a URL safe base64 encoded string' do
|
36
|
+
let(:base64_key) { "t+8lK21q7/44/YTpKTpHa6Icc/a08wIATyhxbVBb4RE=\n" }
|
37
|
+
let(:binary_key) { Base64.decode64(base64_key) }
|
38
|
+
let(:key) { base64_key.gsub('/', '_').gsub('+', '-') }
|
39
|
+
|
40
|
+
it 'is a binary representation of the URL safe base64 encoded string' do
|
41
|
+
expect(subject.key).to eql(binary_key)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'as a binary encoded string' do
|
46
|
+
let(:key) { Ably::Util::Crypto.generate_random_key }
|
47
|
+
|
48
|
+
it 'contains the binary string' do
|
49
|
+
expect(subject.key).to eql(key)
|
50
|
+
expect(subject.key.encoding).to eql(Encoding::ASCII_8BIT)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with an incompatible :key_length constructor param' do
|
55
|
+
let(:key) { Ably::Util::Crypto.generate_random_key(256) }
|
56
|
+
subject { Ably::Models::CipherParams.new(key: key, key_length: 128) }
|
57
|
+
|
58
|
+
it 'raises an exception' do
|
59
|
+
expect { subject }.to raise_error(/Incompatible.*key.*length/)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with an unsupported :key_length for aes-cbc encryption' do
|
64
|
+
let(:key) { "A" * 48 }
|
65
|
+
subject { Ably::Models::CipherParams.new(key: key, algorithm: 'aes', mode: 'cbc') }
|
66
|
+
|
67
|
+
it 'raises an exception' do
|
68
|
+
expect { subject }.to raise_error(/Unsupported key length/)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with an invalid type' do
|
73
|
+
let(:key) { 111 }
|
74
|
+
subject { Ably::Models::CipherParams.new(key: key) }
|
75
|
+
|
76
|
+
it 'raises an exception' do
|
77
|
+
expect { subject }.to raise_error(/key param must/)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'with specified params in the constructor' do
|
84
|
+
let(:key) { Ably::Util::Crypto.generate_random_key(128) }
|
85
|
+
subject { Ably::Models::CipherParams.new(key: key, algorithm: 'aes', key_length: 128, mode: 'cbc') }
|
86
|
+
|
87
|
+
describe '#cipher_type' do
|
88
|
+
it 'contains the complete algorithm string as an upper case string' do
|
89
|
+
expect(subject.cipher_type).to eql ('AES-128-CBC')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#mode' do
|
94
|
+
it 'contains the mode' do
|
95
|
+
expect(subject.mode).to eql ('cbc')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#algorithm' do
|
100
|
+
it 'contains the algorithm' do
|
101
|
+
expect(subject.algorithm).to eql ('aes')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#key_length' do
|
106
|
+
it 'contains the key_length' do
|
107
|
+
expect(subject.key_length).to eql(128)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with combined param in the constructor' do
|
113
|
+
let(:key) { Ably::Util::Crypto.generate_random_key(128) }
|
114
|
+
subject { Ably::Models::CipherParams.new(key: key, combined: "FOO-128-BAR") }
|
115
|
+
|
116
|
+
describe '#cipher_type' do
|
117
|
+
it 'contains the complete algorithm string as an upper case string' do
|
118
|
+
expect(subject.cipher_type).to eql ('FOO-128-BAR')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#mode' do
|
123
|
+
it 'contains the mode' do
|
124
|
+
expect(subject.mode).to eql ('bar')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#algorithm' do
|
129
|
+
it 'contains the algorithm' do
|
130
|
+
expect(subject.algorithm).to eql ('foo')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '#key_length' do
|
135
|
+
it 'contains the key_length' do
|
136
|
+
expect(subject.key_length).to eql(128)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -57,8 +57,8 @@ describe Ably::Models::IdiomaticRubyWrapper, :api_private do
|
|
57
57
|
expect { subject.no_key_exists_for_this }.to raise_error NoMethodError
|
58
58
|
end
|
59
59
|
|
60
|
-
specify '#
|
61
|
-
expect(subject.
|
60
|
+
specify '#attributes returns raw Hash object' do
|
61
|
+
expect(subject.attributes).to eql(mixed_case_data)
|
62
62
|
end
|
63
63
|
|
64
64
|
context 'recursively wrapping child objects' do
|
@@ -153,7 +153,7 @@ describe Ably::Models::IdiomaticRubyWrapper, :api_private do
|
|
153
153
|
end
|
154
154
|
|
155
155
|
it 'uses mixedCase' do
|
156
|
-
expect(subject.
|
156
|
+
expect(subject.attributes['newKey']).to eql('new_value')
|
157
157
|
expect(subject.new_key).to eql('new_value')
|
158
158
|
end
|
159
159
|
end
|
@@ -329,20 +329,27 @@ describe Ably::Models::IdiomaticRubyWrapper, :api_private do
|
|
329
329
|
context '#dup' do
|
330
330
|
let(:mixed_case_data) do
|
331
331
|
{
|
332
|
-
'
|
332
|
+
'key_id' => 'value',
|
333
|
+
'stop' => { client_id: "case won't change" }
|
333
334
|
}.freeze
|
334
335
|
end
|
335
336
|
let(:dupe) { subject.dup }
|
337
|
+
subject { Ably::Models::IdiomaticRubyWrapper.new(mixed_case_data, stop_at: [:stop]) }
|
336
338
|
|
337
339
|
it 'returns a new object with the underlying JSON duped' do
|
338
|
-
expect(subject.
|
339
|
-
expect(dupe.
|
340
|
+
expect(subject.attributes).to be_frozen
|
341
|
+
expect(dupe.attributes).to_not be_frozen
|
340
342
|
end
|
341
343
|
|
342
344
|
it 'returns a new IdiomaticRubyWrapper with the same underlying Hash object' do
|
343
345
|
expect(dupe).to be_a(Ably::Models::IdiomaticRubyWrapper)
|
344
|
-
expect(dupe.
|
345
|
-
expect(dupe.
|
346
|
+
expect(dupe.attributes).to be_a(Hash)
|
347
|
+
expect(dupe.attributes).to eql(mixed_case_data)
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'keeps the stop_at list intact' do
|
351
|
+
expect(dupe.stop_at.keys).to eql([:stop])
|
352
|
+
expect(dupe.attributes['stop']).to eql({ client_id: "case won't change" })
|
346
353
|
end
|
347
354
|
end
|
348
355
|
end
|