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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -2
  3. data/LICENSE +2 -2
  4. data/README.md +81 -20
  5. data/SPEC.md +235 -178
  6. data/lib/ably/auth.rb +1 -1
  7. data/lib/ably/exceptions.rb +10 -1
  8. data/lib/ably/models/cipher_params.rb +114 -0
  9. data/lib/ably/models/connection_details.rb +8 -6
  10. data/lib/ably/models/error_info.rb +3 -3
  11. data/lib/ably/models/idiomatic_ruby_wrapper.rb +27 -20
  12. data/lib/ably/models/message.rb +15 -15
  13. data/lib/ably/models/message_encoders/cipher.rb +8 -7
  14. data/lib/ably/models/presence_message.rb +17 -17
  15. data/lib/ably/models/protocol_message.rb +26 -19
  16. data/lib/ably/models/stats.rb +15 -15
  17. data/lib/ably/models/token_details.rb +14 -12
  18. data/lib/ably/models/token_request.rb +16 -14
  19. data/lib/ably/modules/async_wrapper.rb +1 -1
  20. data/lib/ably/modules/encodeable.rb +10 -10
  21. data/lib/ably/modules/model_common.rb +13 -5
  22. data/lib/ably/realtime/channel.rb +1 -2
  23. data/lib/ably/realtime/presence.rb +29 -58
  24. data/lib/ably/realtime/presence/members_map.rb +2 -2
  25. data/lib/ably/rest/channel.rb +1 -2
  26. data/lib/ably/rest/middleware/exceptions.rb +14 -4
  27. data/lib/ably/rest/presence.rb +3 -1
  28. data/lib/ably/util/crypto.rb +50 -40
  29. data/lib/ably/version.rb +1 -1
  30. data/spec/acceptance/realtime/message_spec.rb +20 -20
  31. data/spec/acceptance/realtime/presence_history_spec.rb +7 -7
  32. data/spec/acceptance/realtime/presence_spec.rb +65 -77
  33. data/spec/acceptance/rest/auth_spec.rb +8 -8
  34. data/spec/acceptance/rest/base_spec.rb +4 -4
  35. data/spec/acceptance/rest/channel_spec.rb +1 -1
  36. data/spec/acceptance/rest/client_spec.rb +1 -1
  37. data/spec/acceptance/rest/encoders_spec.rb +4 -4
  38. data/spec/acceptance/rest/message_spec.rb +15 -15
  39. data/spec/acceptance/rest/presence_spec.rb +4 -4
  40. data/spec/shared/model_behaviour.rb +7 -7
  41. data/spec/unit/models/cipher_params_spec.rb +140 -0
  42. data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +15 -8
  43. data/spec/unit/models/message_encoders/cipher_spec.rb +28 -22
  44. data/spec/unit/models/message_encoders/json_spec.rb +24 -0
  45. data/spec/unit/models/protocol_message_spec.rb +3 -3
  46. data/spec/unit/util/crypto_spec.rb +50 -17
  47. metadata +5 -2
@@ -3,7 +3,7 @@ require 'ably/models/message_encoders/cipher'
3
3
  require 'msgpack'
4
4
 
5
5
  describe Ably::Models::MessageEncoders::Cipher do
6
- let(:secret_key) { random_str(64) }
6
+ let(:secret_key) { Ably::Util::Crypto.generate_random_key(128) }
7
7
  let(:crypto_options) { { key: secret_key, algorithm: 'AES', mode: 'CBC', key_length: 128 } }
8
8
  let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
9
9
 
@@ -23,7 +23,7 @@ describe Ably::Models::MessageEncoders::Cipher do
23
23
 
24
24
  context 'valid cipher data' do
25
25
  before do
26
- subject.decode message, { encrypted: true, cipher_params: cipher_params }
26
+ subject.decode message, { cipher: cipher_params }
27
27
  end
28
28
 
29
29
  context 'message with cipher payload' do
@@ -79,29 +79,33 @@ describe Ably::Models::MessageEncoders::Cipher do
79
79
  end
80
80
  end
81
81
 
82
- context 'with invalid channel_option cipher params' do
83
- let(:message) { { data: decoded_data, encoding: 'cipher+aes-128-cbc' } }
84
- let(:cipher_params) { crypto_options.merge(key_length: 256) }
85
- let(:decode_method) { subject.decode message, { encrypted: true, cipher_params: cipher_params } }
82
+ context '256 bit key' do
83
+ let(:secret_key) { Ably::Util::Crypto.generate_random_key(256) }
86
84
 
87
- it 'raise an exception' do
88
- expect { decode_method }.to raise_error Ably::Exceptions::CipherError, /Cipher algorithm [\w-]+ does not match message cipher algorithm of AES-128-CBC/
85
+ context 'with invalid channel_option cipher params' do
86
+ let(:message) { { data: decoded_data, encoding: 'cipher+aes-128-cbc' } }
87
+ let(:cipher_params) { crypto_options.merge(key_length: 256) }
88
+ let(:decode_method) { subject.decode message, { cipher: cipher_params } }
89
+
90
+ it 'raise an exception' do
91
+ expect { decode_method }.to raise_error Ably::Exceptions::CipherError, /Cipher algorithm [\w-]+ does not match message cipher algorithm of AES-128-CBC/
92
+ end
89
93
  end
90
- end
91
94
 
92
- context 'without any configured encryption' do
93
- let(:message) { { data: decoded_data, encoding: 'cipher+aes-128-cbc' } }
94
- let(:cipher_params) { crypto_options.merge(key_length: 256) }
95
- let(:decode_method) { subject.decode message, {} }
95
+ context 'without any configured encryption' do
96
+ let(:message) { { data: decoded_data, encoding: 'cipher+aes-128-cbc' } }
97
+ let(:cipher_params) { crypto_options.merge(key_length: 256) }
98
+ let(:decode_method) { subject.decode message, {} }
96
99
 
97
- it 'raise an exception' do
98
- expect { decode_method }.to raise_error Ably::Exceptions::CipherError, /Message cannot be decrypted as the channel is not set up for encryption & decryption/
100
+ it 'raise an exception' do
101
+ expect { decode_method }.to raise_error Ably::Exceptions::CipherError, /Message cannot be decrypted as the channel is not set up for encryption & decryption/
102
+ end
99
103
  end
100
104
  end
101
105
 
102
106
  context 'with invalid cipher data' do
103
107
  let(:message) { { data: decoded_data, encoding: 'cipher+aes-128-cbc' } }
104
- let(:decode_method) { subject.decode(message, { encrypted: true, cipher_params: cipher_params }) }
108
+ let(:decode_method) { subject.decode(message, { cipher: cipher_params }) }
105
109
 
106
110
  it 'raise an exception' do
107
111
  expect { decode_method }.to raise_error Ably::Exceptions::CipherError, /CipherError decrypting data/
@@ -110,10 +114,11 @@ describe Ably::Models::MessageEncoders::Cipher do
110
114
  end
111
115
 
112
116
  context 'with AES-256-CBC' do
117
+ let(:secret_key) { Ably::Util::Crypto.generate_random_key(256) }
113
118
  let(:cipher_params) { crypto_options.merge(key_length: 256) }
114
119
 
115
120
  before do
116
- subject.decode message, { encrypted: true, cipher_params: cipher_params }
121
+ subject.decode message, { cipher: cipher_params }
117
122
  end
118
123
 
119
124
  context 'message with cipher payload' do
@@ -133,7 +138,7 @@ describe Ably::Models::MessageEncoders::Cipher do
133
138
  context '#encode' do
134
139
  context 'with channel set up for AES-128-CBC' do
135
140
  let(:cipher_params) { crypto_options }
136
- let(:channel_options) { { encrypted: true, cipher_params: cipher_params } }
141
+ let(:channel_options) { { cipher: cipher_params } }
137
142
 
138
143
  context 'with encrypted set to true' do
139
144
  before do
@@ -211,12 +216,12 @@ describe Ably::Models::MessageEncoders::Cipher do
211
216
 
212
217
  context 'channel_option cipher params' do
213
218
  let(:message) { { data: decoded_data, encoding: nil } }
214
- let(:encode_method) { subject.encode message, { encrypted: true, cipher_params: cipher_params } }
219
+ let(:encode_method) { subject.encode message, { cipher: cipher_params } }
215
220
 
216
221
  context 'have invalid key length' do
217
222
  let(:cipher_params) { crypto_options.merge(key_length: 1) }
218
223
  it 'raise an exception' do
219
- expect { encode_method }.to raise_error Ably::Exceptions::CipherError, /unsupported cipher algorithm/
224
+ expect { encode_method }.to raise_error Ably::Exceptions::CipherError, /Incompatible :key length/
220
225
  end
221
226
  end
222
227
 
@@ -230,17 +235,18 @@ describe Ably::Models::MessageEncoders::Cipher do
230
235
  context 'have missing key' do
231
236
  let(:cipher_params) { {} }
232
237
  it 'raise an exception' do
233
- expect { encode_method }.to raise_error Ably::Exceptions::CipherError, /:key is required/
238
+ expect { encode_method }.to raise_error Ably::Exceptions::CipherError, /key.*required/
234
239
  end
235
240
  end
236
241
  end
237
242
  end
238
243
 
239
244
  context 'with AES-256-CBC' do
245
+ let(:secret_key) { Ably::Util::Crypto.generate_random_key(256) }
240
246
  let(:cipher_params) { crypto_options.merge(key_length: 256) }
241
247
 
242
248
  before do
243
- subject.encode message, { encrypted: true, cipher_params: cipher_params }
249
+ subject.encode message, { cipher: cipher_params }
244
250
  end
245
251
 
246
252
  context 'message with cipher payload' do
@@ -30,6 +30,18 @@ describe Ably::Models::MessageEncoders::Json do
30
30
  end
31
31
  end
32
32
 
33
+ context 'message with json payload in camelCase' do
34
+ let(:message) { { data: '{"keyId":"test"}', encoding: 'json' } }
35
+
36
+ it 'decodes json' do
37
+ expect(message[:data]).to eq({ 'keyId' => 'test' })
38
+ end
39
+
40
+ it 'strips the encoding' do
41
+ expect(message[:encoding]).to be_nil
42
+ end
43
+ end
44
+
33
45
  context 'message with json payload before other payloads' do
34
46
  let(:message) { { data: hash_string_data, encoding: 'utf-8/json' } }
35
47
 
@@ -72,6 +84,18 @@ describe Ably::Models::MessageEncoders::Json do
72
84
  end
73
85
  end
74
86
 
87
+ context 'message with hash payload and underscore case keys' do
88
+ let(:message) { { data: { key_id: 'test' }, encoding: nil } }
89
+
90
+ it 'encodes hash payload data as json and leaves underscore case in tact' do
91
+ expect(message[:data]).to eql('{"key_id":"test"}')
92
+ end
93
+
94
+ it 'adds the encoding' do
95
+ expect(message[:encoding]).to eql('json')
96
+ end
97
+ end
98
+
75
99
  context 'already encoded message with hash payload' do
76
100
  let(:message) { { data: hash_data, encoding: 'utf-8' } }
77
101
 
@@ -20,17 +20,17 @@ describe Ably::Models::ProtocolMessage do
20
20
  context 'initializer action coercion', :api_private do
21
21
  it 'ignores actions that are Integers' do
22
22
  protocol_message = subject.new(action: 14)
23
- expect(protocol_message.hash[:action]).to eql(14)
23
+ expect(protocol_message.attributes[:action]).to eql(14)
24
24
  end
25
25
 
26
26
  it 'converts actions to Integers if a symbol' do
27
27
  protocol_message = subject.new(action: :message)
28
- expect(protocol_message.hash[:action]).to eql(15)
28
+ expect(protocol_message.attributes[:action]).to eql(15)
29
29
  end
30
30
 
31
31
  it 'converts actions to Integers if a ACTION' do
32
32
  protocol_message = subject.new(action: Ably::Models::ProtocolMessage::ACTION.Message)
33
- expect(protocol_message.hash[:action]).to eql(15)
33
+ expect(protocol_message.attributes[:action]).to eql(15)
34
34
  end
35
35
 
36
36
  it 'raises an argument error if nil' do
@@ -2,16 +2,17 @@ require 'spec_helper'
2
2
  require 'msgpack'
3
3
 
4
4
  describe Ably::Util::Crypto do
5
- let(:seret_key) { random_str }
6
- let(:cipher_options) { { key: seret_key } }
5
+ let(:cipher) { OpenSSL::Cipher.new('AES-256-CBC') }
6
+ let(:secret_key) { cipher.random_key }
7
+ let(:cipher_options) { { key: secret_key } }
7
8
  subject { Ably::Util::Crypto.new(cipher_options) }
8
9
 
9
10
  context 'defaults' do
10
11
  let(:expected_defaults) do
11
12
  {
12
- algorithm: 'AES',
13
- mode: 'CBC',
14
- key_length: 128
13
+ algorithm: 'aes',
14
+ mode: 'cbc',
15
+ key_length: 256
15
16
  }
16
17
  end
17
18
 
@@ -22,20 +23,52 @@ describe Ably::Util::Crypto do
22
23
  end
23
24
 
24
25
  context 'get_default_params' do
25
- it 'uses the defaults and generates a key if not provided' do
26
- expect(Ably::Util::Crypto.get_default_params[:algorithm]).to eql('AES')
27
- expect(Ably::Util::Crypto.get_default_params[:mode]).to eql('CBC')
28
- expect(Ably::Util::Crypto.get_default_params[:key_length]).to eql(128)
29
- expect(Ably::Util::Crypto.get_default_params[:key].unpack('b*').first.length).to eql(128)
26
+ context 'with just a :key param' do
27
+ let(:defaults) { Ably::Util::Crypto.get_default_params(key: secret_key) }
28
+
29
+ it 'uses the defaults' do
30
+ expect(defaults.algorithm).to eql('aes')
31
+ expect(defaults.mode).to eql('cbc')
32
+ expect(defaults.key_length).to eql(256)
33
+ end
34
+
35
+ it 'contains the provided key' do
36
+ expect(defaults.key).to eql(secret_key)
37
+ end
38
+
39
+ it 'returns a CipherParams object' do
40
+ expect(defaults).to be_a(Ably::Models::CipherParams)
41
+ end
30
42
  end
31
43
 
32
- it 'uses the defaults and sets the key size when key is provided' do
33
- key_192 = '123456781234567812345678'
34
- params = Ably::Util::Crypto.get_default_params(key_192)
35
- expect(params[:algorithm]).to eql('AES')
36
- expect(params[:mode]).to eql('CBC')
37
- expect(params[:key_length]).to eql(192)
38
- expect(params[:key]).to eql(key_192)
44
+ context 'without a :key param' do
45
+ let(:cipher_params) { Ably::Util::Crypto.get_default_params }
46
+
47
+ it 'raises an exception' do
48
+ expect { cipher_params }.to raise_error(/key.*required/)
49
+ end
50
+ end
51
+
52
+ context 'with a base64-encoded :key param' do
53
+ let(:cipher_params) { Ably::Util::Crypto.get_default_params(key: Base64.encode64(secret_key)) }
54
+
55
+ it 'converts the key to binary' do
56
+ expect(cipher_params.key).to eql(secret_key)
57
+ end
58
+ end
59
+
60
+ context 'with provided params' do
61
+ let(:algorithm) { 'FOO' }
62
+ let(:mode) { 'BAR' }
63
+ let(:key_length) { 192 }
64
+ let(:key) { secret_key[0...24] }
65
+ let(:cipher_params) { Ably::Util::Crypto.get_default_params(key: key, algorithm: algorithm, mode: mode, key_length: key_length) }
66
+
67
+ it 'overrides the defaults' do
68
+ expect(cipher_params.algorithm).to eql('foo')
69
+ expect(cipher_params.mode).to eql('bar')
70
+ expect(cipher_params.key_length).to eql(192)
71
+ end
39
72
  end
40
73
  end
41
74
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ably
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.8
4
+ version: 0.8.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lewis Marshall
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-01-26 00:00:00.000000000 Z
12
+ date: 2016-03-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -287,6 +287,7 @@ files:
287
287
  - lib/ably/exceptions.rb
288
288
  - lib/ably/logger.rb
289
289
  - lib/ably/models/channel_state_change.rb
290
+ - lib/ably/models/cipher_params.rb
290
291
  - lib/ably/models/connection_details.rb
291
292
  - lib/ably/models/connection_state_change.rb
292
293
  - lib/ably/models/error_info.rb
@@ -397,6 +398,7 @@ files:
397
398
  - spec/unit/auth_spec.rb
398
399
  - spec/unit/logger_spec.rb
399
400
  - spec/unit/models/channel_state_change_spec.rb
401
+ - spec/unit/models/cipher_params_spec.rb
400
402
  - spec/unit/models/connection_details_spec.rb
401
403
  - spec/unit/models/connection_state_change_spec.rb
402
404
  - spec/unit/models/error_info_spec.rb
@@ -497,6 +499,7 @@ test_files:
497
499
  - spec/unit/auth_spec.rb
498
500
  - spec/unit/logger_spec.rb
499
501
  - spec/unit/models/channel_state_change_spec.rb
502
+ - spec/unit/models/cipher_params_spec.rb
500
503
  - spec/unit/models/connection_details_spec.rb
501
504
  - spec/unit/models/connection_state_change_spec.rb
502
505
  - spec/unit/models/error_info_spec.rb