ably-rest 0.8.5 → 0.8.6

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/SPEC.md +1380 -631
  4. data/ably-rest.gemspec +11 -5
  5. data/lib/submodules/ably-ruby/.travis.yml +1 -1
  6. data/lib/submodules/ably-ruby/CHANGELOG.md +42 -48
  7. data/lib/submodules/ably-ruby/ably.gemspec +7 -1
  8. data/lib/submodules/ably-ruby/lib/ably.rb +2 -0
  9. data/lib/submodules/ably-ruby/lib/ably/auth.rb +155 -47
  10. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +2 -0
  11. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +2 -3
  12. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +54 -0
  13. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +14 -4
  14. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +13 -7
  15. data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +1 -2
  16. data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +3 -2
  17. data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +1 -3
  18. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +2 -2
  19. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +6 -0
  20. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +15 -4
  21. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +2 -0
  22. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +10 -3
  23. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +11 -1
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +62 -6
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +58 -54
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +18 -5
  27. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +9 -1
  28. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +32 -14
  29. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
  30. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  31. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +251 -11
  32. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +12 -2
  33. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +316 -24
  34. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +93 -1
  35. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +177 -86
  36. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +284 -60
  37. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +45 -6
  38. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +4 -0
  39. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +181 -49
  40. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +13 -0
  41. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +222 -4
  42. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +132 -1
  43. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +129 -28
  44. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +7 -7
  45. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +10 -0
  46. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +41 -17
  47. data/lib/submodules/ably-ruby/spec/spec_helper.rb +1 -0
  48. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +16 -0
  49. data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +60 -0
  50. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +45 -0
  51. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +3 -1
  52. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +6 -5
  53. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +5 -1
  54. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +5 -1
  55. data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +5 -1
  56. metadata +57 -13
@@ -14,10 +14,10 @@ Gem::Specification.new do |spec|
14
14
  spec.version = Ably::VERSION
15
15
  spec.authors = ['Matthew O\'Riordan']
16
16
  spec.email = ['matt@ably.io']
17
- spec.description = %q{A Ruby REST only client library for ably.io, the real-time messaging service}
18
- spec.summary = %q{A Ruby REST only client library for ably.io, the real-time messaging service}
17
+ spec.description = %q{A Ruby REST only client library for ably.io realtime messaging}
18
+ spec.summary = %q{A Ruby REST only client library for ably.io realtime messaging}
19
19
  spec.homepage = 'http://github.com/ably/ably-ruby-rest'
20
- spec.license = 'MIT'
20
+ spec.license = 'Apache 2'
21
21
 
22
22
  submodule_path = File.expand_path('../lib/submodules/ably-ruby', __FILE__)
23
23
  submodule_files = Dir.chdir(submodule_path) do
@@ -33,13 +33,19 @@ Gem::Specification.new do |spec|
33
33
 
34
34
  spec.add_runtime_dependency 'faraday', '~> 0.9'
35
35
  spec.add_runtime_dependency 'json'
36
- spec.add_runtime_dependency 'msgpack-ably', '~> 0.5.10'
36
+ spec.add_runtime_dependency 'msgpack', '>= 0.6.2'
37
+ spec.add_runtime_dependency 'addressable', '>= 2.0.0'
37
38
 
38
39
  spec.add_development_dependency 'bundler', '~> 1.3'
39
40
  spec.add_development_dependency 'rake'
40
41
  spec.add_development_dependency 'redcarpet'
41
- spec.add_development_dependency 'rspec', '~> 3.0'
42
+ spec.add_development_dependency 'rspec', '~> 3.2.0'
42
43
  spec.add_development_dependency 'rspec-retry'
43
44
  spec.add_development_dependency 'yard'
44
45
  spec.add_development_dependency 'webmock'
46
+
47
+ if RUBY_VERSION.match(/^2/)
48
+ spec.add_development_dependency 'pry'
49
+ spec.add_development_dependency 'pry-byebug'
50
+ end
45
51
  end
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
- env: RSPEC_RETRY=true
2
+ env: RSPEC_RETRY=false
3
3
  language: ruby
4
4
  rvm:
5
5
  - 1.9.3
@@ -1,29 +1,59 @@
1
1
  # Change Log
2
2
 
3
- ## [Unreleased](https://github.com/ably/ably-ruby/tree/HEAD)
3
+ ## [v0.8.6](https://github.com/ably/ably-ruby/tree/v0.8.6) (2015-12-02)
4
4
 
5
- [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.2...HEAD)
5
+ [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.5...v0.8.6)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - Some intermittent test fixes & enable tests that were blocked [\#70](https://github.com/ably/ably-ruby/pull/70) ([mattheworiordan](https://github.com/mattheworiordan))
10
+
11
+ - Output detailed log for any text failures [\#67](https://github.com/ably/ably-ruby/pull/67) ([mattheworiordan](https://github.com/mattheworiordan))
12
+
13
+ - 0.8 final spec \(98% compliance\) [\#66](https://github.com/ably/ably-ruby/pull/66) ([mattheworiordan](https://github.com/mattheworiordan))
14
+
15
+ ## [v0.8.5](https://github.com/ably/ably-ruby/tree/v0.8.5) (2015-10-08)
16
+ [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.4...v0.8.5)
6
17
 
7
18
  **Implemented enhancements:**
8
19
 
9
- - Add compatibility support for default Crypto params [\#53](https://github.com/ably/ably-ruby/issues/53)
20
+ - Switch arity of auth methods [\#61](https://github.com/ably/ably-ruby/issues/61)
10
21
 
11
- - EventEmitter on connection [\#52](https://github.com/ably/ably-ruby/issues/52)
22
+ **Fixed bugs:**
12
23
 
24
+ - Switch arity of auth methods [\#61](https://github.com/ably/ably-ruby/issues/61)
25
+ - Add test: Message published, connection dropped, then restores to point before last message was published [\#56](https://github.com/ably/ably-ruby/issues/56)
26
+ - Documentation for constructor is incorrect [\#49](https://github.com/ably/ably-ruby/issues/49)
27
+
28
+ **Merged pull requests:**
29
+
30
+ - Ensure connections are always closed in tests [\#63](https://github.com/ably/ably-ruby/pull/63) ([mattheworiordan](https://github.com/mattheworiordan))
31
+
32
+ ## [v0.8.4](https://github.com/ably/ably-ruby/tree/v0.8.4) (2015-09-08)
33
+ [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.3...v0.8.4)
34
+
35
+ **Implemented enhancements:**
36
+
37
+ - Add compatibility support for default Crypto params [\#53](https://github.com/ably/ably-ruby/issues/53)
38
+ - EventEmitter on connection [\#52](https://github.com/ably/ably-ruby/issues/52)
13
39
  - Add test for connectionId attribute for a message sent over REST [\#50](https://github.com/ably/ably-ruby/issues/50)
14
40
 
15
- - Implement :queue\_messages option [\#36](https://github.com/ably/ably-ruby/issues/36)
41
+ **Merged pull requests:**
16
42
 
17
- - Check that a non 200-299 status code for REST requests uses fallback hosts [\#35](https://github.com/ably/ably-ruby/issues/35)
43
+ - Spec update to fix a number of issues [\#60](https://github.com/ably/ably-ruby/pull/60) ([mattheworiordan](https://github.com/mattheworiordan))
44
+ - Allow clientId to be provided on init if using externally created token [\#58](https://github.com/ably/ably-ruby/pull/58) ([SimonWoolf](https://github.com/SimonWoolf))
18
45
 
19
- - Move stats fixtures into ably-common [\#34](https://github.com/ably/ably-ruby/issues/34)
46
+ ## [v0.8.3](https://github.com/ably/ably-ruby/tree/v0.8.3) (2015-08-19)
47
+ [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.2...v0.8.3)
20
48
 
21
- - Add tests for messages with no data or name fields [\#21](https://github.com/ably/ably-ruby/issues/21)
49
+ **Implemented enhancements:**
22
50
 
51
+ - Implement :queue\_messages option [\#36](https://github.com/ably/ably-ruby/issues/36)
52
+ - Check that a non 200-299 status code for REST requests uses fallback hosts [\#35](https://github.com/ably/ably-ruby/issues/35)
53
+ - Move stats fixtures into ably-common [\#34](https://github.com/ably/ably-ruby/issues/34)
54
+ - Add tests for messages with no data or name fields [\#21](https://github.com/ably/ably-ruby/issues/21)
23
55
  - Namespace MsgPack as MsgPack5 because compliance is not merged in [\#12](https://github.com/ably/ably-ruby/issues/12)
24
-
25
56
  - Add test coverage for receiving messages more than once i.e. historical messages resent somehow on reconnect [\#11](https://github.com/ably/ably-ruby/issues/11)
26
-
27
57
  - Add async methods for Authentication in the realtime library [\#8](https://github.com/ably/ably-ruby/issues/8)
28
58
 
29
59
  **Fixed bugs:**
@@ -33,41 +63,28 @@
33
63
  **Closed issues:**
34
64
 
35
65
  - Scope default token params in arguments [\#55](https://github.com/ably/ably-ruby/issues/55)
36
-
37
66
  - Channel options can be reset when accessing a channel with \#get [\#46](https://github.com/ably/ably-ruby/issues/46)
38
67
 
39
68
  **Merged pull requests:**
40
69
 
41
- - Spec update to fix a number of issues [\#60](https://github.com/ably/ably-ruby/pull/60) ([mattheworiordan](https://github.com/mattheworiordan))
42
-
43
- - Allow clientId to be provided on init if using externally created token [\#58](https://github.com/ably/ably-ruby/pull/58) ([SimonWoolf](https://github.com/SimonWoolf))
44
-
45
70
  - Separate token params for auth [\#57](https://github.com/ably/ably-ruby/pull/57) ([mattheworiordan](https://github.com/mattheworiordan))
46
-
47
71
  - Ensure files are required in a consistent order [\#51](https://github.com/ably/ably-ruby/pull/51) ([SimonWoolf](https://github.com/SimonWoolf))
48
72
 
49
73
  ## [v0.8.2](https://github.com/ably/ably-ruby/tree/v0.8.2) (2015-05-20)
50
-
51
74
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.1...v0.8.2)
52
75
 
53
76
  **Implemented enhancements:**
54
77
 
55
78
  - Ensure Array object can be used in place of Hash for payload [\#44](https://github.com/ably/ably-ruby/issues/44)
56
-
57
79
  - Change connect\_automatically option to auto\_connect for consistency [\#42](https://github.com/ably/ably-ruby/issues/42)
58
-
59
80
  - Rename PaginatedResource to PaginatedResult for consistency [\#40](https://github.com/ably/ably-ruby/issues/40)
60
-
61
81
  - EventEmitter should use `emit` not `trigger` to be consistent with other libs [\#31](https://github.com/ably/ably-ruby/issues/31)
62
-
63
82
  - Add exceptions when data attribute for messages/presence is not String, Binary or JSON data [\#4](https://github.com/ably/ably-ruby/issues/4)
64
-
65
83
  - Auth Callback and Auth URL should support tokens as well as token requests [\#2](https://github.com/ably/ably-ruby/issues/2)
66
84
 
67
85
  **Closed issues:**
68
86
 
69
87
  - Realtime Presence\#get does not wait by default [\#47](https://github.com/ably/ably-ruby/issues/47)
70
-
71
88
  - No implicit attach when accessing channel.presence [\#45](https://github.com/ably/ably-ruby/issues/45)
72
89
 
73
90
  **Merged pull requests:**
@@ -75,11 +92,9 @@
75
92
  - Reject invalid payload type [\#48](https://github.com/ably/ably-ruby/pull/48) ([mattheworiordan](https://github.com/mattheworiordan))
76
93
 
77
94
  ## [v0.8.1](https://github.com/ably/ably-ruby/tree/v0.8.1) (2015-04-23)
78
-
79
95
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.0...v0.8.1)
80
96
 
81
97
  ## [v0.8.0](https://github.com/ably/ably-ruby/tree/v0.8.0) (2015-04-23)
82
-
83
98
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.7.6...v0.8.0)
84
99
 
85
100
  **Merged pull requests:**
@@ -87,18 +102,15 @@
87
102
  - Token naming refactor [\#29](https://github.com/ably/ably-ruby/pull/29) ([mattheworiordan](https://github.com/mattheworiordan))
88
103
 
89
104
  ## [v0.7.6](https://github.com/ably/ably-ruby/tree/v0.7.6) (2015-04-17)
90
-
91
105
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.7.5...v0.7.6)
92
106
 
93
107
  **Implemented enhancements:**
94
108
 
95
109
  - Rename Stat to Stats for consistency [\#32](https://github.com/ably/ably-ruby/issues/32)
96
-
97
110
  - Stats objects [\#24](https://github.com/ably/ably-ruby/issues/24)
98
-
99
111
  - Need a test to handle errors in callbacks [\#13](https://github.com/ably/ably-ruby/issues/13)
100
-
101
112
  - Allow token ID or API key in the client constructor [\#5](https://github.com/ably/ably-ruby/issues/5)
113
+ - Typed stats similar to Java library + zero default for empty stats [\#25](https://github.com/ably/ably-ruby/pull/25) ([mattheworiordan](https://github.com/mattheworiordan))
102
114
 
103
115
  **Fixed bugs:**
104
116
 
@@ -111,19 +123,14 @@
111
123
  **Merged pull requests:**
112
124
 
113
125
  - Test encoded presence fixture data for \#get & \#history [\#28](https://github.com/ably/ably-ruby/pull/28) ([mattheworiordan](https://github.com/mattheworiordan))
114
-
115
126
  - Add coveralls.io coverage reporting [\#27](https://github.com/ably/ably-ruby/pull/27) ([mattheworiordan](https://github.com/mattheworiordan))
116
-
117
127
  - New paginated resource [\#26](https://github.com/ably/ably-ruby/pull/26) ([mattheworiordan](https://github.com/mattheworiordan))
118
-
119
- - Typed stats similar to Java library + zero default for empty stats [\#25](https://github.com/ably/ably-ruby/pull/25) ([mattheworiordan](https://github.com/mattheworiordan))
128
+ - History since attach [\#22](https://github.com/ably/ably-ruby/pull/22) ([mattheworiordan](https://github.com/mattheworiordan))
120
129
 
121
130
  ## [v0.7.5](https://github.com/ably/ably-ruby/tree/v0.7.5) (2015-03-21)
122
-
123
131
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.7.4...v0.7.5)
124
132
 
125
133
  ## [v0.7.4](https://github.com/ably/ably-ruby/tree/v0.7.4) (2015-03-21)
126
-
127
134
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.7.2...v0.7.4)
128
135
 
129
136
  **Merged pull requests:**
@@ -131,7 +138,6 @@
131
138
  - Presence Member Map [\#14](https://github.com/ably/ably-ruby/pull/14) ([mattheworiordan](https://github.com/mattheworiordan))
132
139
 
133
140
  ## [v0.7.2](https://github.com/ably/ably-ruby/tree/v0.7.2) (2015-02-10)
134
-
135
141
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.7.1...v0.7.2)
136
142
 
137
143
  **Implemented enhancements:**
@@ -141,15 +147,12 @@
141
147
  **Merged pull requests:**
142
148
 
143
149
  - Update README to include various missing snippets for core features [\#9](https://github.com/ably/ably-ruby/pull/9) ([kouno](https://github.com/kouno))
144
-
145
150
  - Fix connection retry frequency [\#7](https://github.com/ably/ably-ruby/pull/7) ([kouno](https://github.com/kouno))
146
151
 
147
152
  ## [v0.7.1](https://github.com/ably/ably-ruby/tree/v0.7.1) (2015-01-18)
148
-
149
153
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.7.0...v0.7.1)
150
154
 
151
155
  ## [v0.7.0](https://github.com/ably/ably-ruby/tree/v0.7.0) (2015-01-12)
152
-
153
156
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.6.2...v0.7.0)
154
157
 
155
158
  **Closed issues:**
@@ -157,39 +160,30 @@
157
160
  - JSON encoder should only append utf-8 before a cipher encoder is applied [\#1](https://github.com/ably/ably-ruby/issues/1)
158
161
 
159
162
  ## [v0.6.2](https://github.com/ably/ably-ruby/tree/v0.6.2) (2014-12-10)
160
-
161
163
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.2.0...v0.6.2)
162
164
 
163
165
  ## [v0.2.0](https://github.com/ably/ably-ruby/tree/v0.2.0) (2014-12-09)
164
-
165
166
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.1.6...v0.2.0)
166
167
 
167
168
  ## [v0.1.6](https://github.com/ably/ably-ruby/tree/v0.1.6) (2014-10-31)
168
-
169
169
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.1.5...v0.1.6)
170
170
 
171
171
  ## [v0.1.5](https://github.com/ably/ably-ruby/tree/v0.1.5) (2014-10-23)
172
-
173
172
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.1.4...v0.1.5)
174
173
 
175
174
  ## [v0.1.4](https://github.com/ably/ably-ruby/tree/v0.1.4) (2014-09-27)
176
-
177
175
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.1.3...v0.1.4)
178
176
 
179
177
  ## [v0.1.3](https://github.com/ably/ably-ruby/tree/v0.1.3) (2014-09-26)
180
-
181
178
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.1.2...v0.1.3)
182
179
 
183
180
  ## [v0.1.2](https://github.com/ably/ably-ruby/tree/v0.1.2) (2014-09-25)
184
-
185
181
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.1.1...v0.1.2)
186
182
 
187
183
  ## [v0.1.1](https://github.com/ably/ably-ruby/tree/v0.1.1) (2014-09-23)
188
-
189
184
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v0.1.0...v0.1.1)
190
185
 
191
186
  ## [v0.1.0](https://github.com/ably/ably-ruby/tree/v0.1.0) (2014-09-23)
192
187
 
193
188
 
194
-
195
189
  \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
@@ -25,14 +25,20 @@ Gem::Specification.new do |spec|
25
25
  spec.add_runtime_dependency 'json'
26
26
  spec.add_runtime_dependency 'websocket-driver', '~> 0.3'
27
27
  spec.add_runtime_dependency 'msgpack', '>= 0.6.2'
28
+ spec.add_runtime_dependency 'addressable', '>= 2.0.0'
28
29
 
29
30
  spec.add_development_dependency 'bundler', '~> 1.3'
30
31
  spec.add_development_dependency 'rake'
31
32
  spec.add_development_dependency 'redcarpet'
32
- spec.add_development_dependency 'rspec', '~> 3.1.0' # version lock, see config.around(:example, :event_machine) in event_machine_helper.rb
33
+ spec.add_development_dependency 'rspec', '~> 3.2.0' # version lock, see config.around(:example, :event_machine) in event_machine_helper.rb
33
34
  spec.add_development_dependency 'rspec-retry'
34
35
  spec.add_development_dependency 'yard'
35
36
  spec.add_development_dependency 'webmock'
36
37
 
37
38
  spec.add_development_dependency 'coveralls'
39
+
40
+ if RUBY_VERSION.match(/^2/)
41
+ spec.add_development_dependency 'pry'
42
+ spec.add_development_dependency 'pry-byebug'
43
+ end
38
44
  end
@@ -1,3 +1,5 @@
1
+ require 'addressable/uri'
2
+
1
3
  %w(modules util).each do |namespace|
2
4
  Dir.glob(File.expand_path("ably/#{namespace}/*.rb", File.dirname(__FILE__))).sort.each do |file|
3
5
  require file
@@ -13,8 +13,6 @@ module Ably
13
13
  # @return [String] The provided client ID, used for identifying this client for presence purposes
14
14
  # @!attribute [r] current_token_details
15
15
  # @return [Ably::Models::TokenDetails] Current {Ably::Models::TokenDetails} issued by this library or one of the provided callbacks used to authenticate requests
16
- # @!attribute [r] token
17
- # @return [String] Token string provided to the {Ably::Client} constructor that is used to authenticate all requests
18
16
  # @!attribute [r] key
19
17
  # @return [String] Complete API key containing both the key name and key secret, if present
20
18
  # @!attribute [r] key_name
@@ -61,6 +59,7 @@ module Ably
61
59
  @client = client
62
60
  @options = auth_options.dup
63
61
  @token_params = token_params.dup
62
+ @token_option = options[:token] || options[:token_details]
64
63
 
65
64
  @options.delete :force # Forcing token auth for every request is not a valid default
66
65
 
@@ -74,11 +73,25 @@ module Ably
74
73
  raise ArgumentError, 'key is missing. Either an API key, token, or token auth method must be provided'
75
74
  end
76
75
 
77
- if has_client_id? && !token_creatable_externally?
78
- raise ArgumentError, 'client_id cannot be provided without a complete API key. Key name & Secret is needed to authenticate with Ably and obtain a token' unless api_key_present?
76
+ if options[:client_id] == '*'
77
+ raise ArgumentError, 'A client cannot be configured with a wildcard client_id'
78
+ end
79
+
80
+ if has_client_id? && !token_creatable_externally? && !token_option
81
+ raise ArgumentError, 'client_id cannot be provided without a complete API key or means to authenticate. An API key is needed to automatically authenticate with Ably and obtain a token' unless api_key_present?
79
82
  ensure_utf_8 :client_id, client_id
80
83
  end
81
84
 
85
+ # If a token details object or token string is provided in the initializer
86
+ # then the client can be authorised immediately using this token
87
+ if token_option
88
+ token_details = convert_to_token_details(token_option)
89
+ if token_details
90
+ token_details = authorise_with_token(token_details)
91
+ logger.debug "Auth: new token passed in to the initializer: #{token_details}"
92
+ end
93
+ end
94
+
82
95
  @options.freeze
83
96
  @token_params.freeze
84
97
  end
@@ -120,7 +133,9 @@ module Ably
120
133
  token_params = (auth_options.delete(:token_params) || {}).merge(token_params)
121
134
  @token_params = @token_params.merge(token_params) # update defaults
122
135
 
123
- @current_token_details = request_token(token_params, auth_options)
136
+ authorise_with_token(request_token(token_params, auth_options)).tap do |new_token_details|
137
+ logger.debug "Auth: new token following authorisation: #{new_token_details}"
138
+ end
124
139
  end
125
140
 
126
141
  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
@@ -154,34 +169,29 @@ module Ably
154
169
  def request_token(token_params = {}, auth_options = {})
155
170
  ensure_valid_auth_attributes auth_options
156
171
 
157
- token_params = (auth_options[:token_params] || {}).merge(token_params)
158
- token_params = self.token_params.merge(token_params)
172
+ # Token param precedence (lowest to highest):
173
+ # Auth default => client_id => auth_options[:token_params] arg => token_params arg
174
+ token_params = self.token_params.merge(
175
+ (client_id ? { client_id: client_id } : {}).
176
+ merge(auth_options[:token_params] || {}).
177
+ merge(token_params)
178
+ )
179
+
159
180
  auth_options = self.options.merge(auth_options)
160
181
 
161
182
  token_request = if auth_callback = auth_options.delete(:auth_callback)
162
183
  auth_callback.call(token_params)
163
184
  elsif auth_url = auth_options.delete(:auth_url)
164
- token_request_from_auth_url(auth_url, auth_options)
185
+ token_request_from_auth_url(auth_url, auth_options, token_params)
165
186
  else
166
187
  create_token_request(token_params, auth_options)
167
188
  end
168
189
 
169
- case token_request
170
- when Ably::Models::TokenDetails
171
- return token_request
172
- when Hash
173
- return Ably::Models::TokenDetails.new(token_request) if IdiomaticRubyWrapper(token_request).has_key?(:issued)
174
- when String
175
- return Ably::Models::TokenDetails.new(token: token_request)
190
+ convert_to_token_details(token_request).tap do |token_details|
191
+ return token_details if token_details
176
192
  end
177
193
 
178
- token_request = Ably::Models::TokenRequest(token_request)
179
-
180
- response = client.post("/keys/#{token_request.key_name}/requestToken",
181
- token_request.hash, send_auth_header: false,
182
- disable_automatic_reauthorise: true)
183
-
184
- Ably::Models::TokenDetails.new(response.body)
194
+ send_token_request(token_request)
185
195
  end
186
196
 
187
197
  # Creates and signs a token request that can then subsequently be used by any client to request a token
@@ -277,21 +287,23 @@ module Ably
277
287
  # True when Token Auth is being used to authenticate with Ably
278
288
  def using_token_auth?
279
289
  return options[:use_token_auth] if options.has_key?(:use_token_auth)
280
- !!(token || current_token_details || has_client_id? || token_creatable_externally?)
290
+ !!(token_option || current_token_details || has_client_id? || token_creatable_externally?)
281
291
  end
282
292
 
283
293
  def client_id
284
- options[:client_id]
294
+ @client_id || options[:client_id]
285
295
  end
286
296
 
287
- def token
288
- token_object = options[:token] || options[:token_details]
289
-
290
- if token_object.kind_of?(Ably::Models::TokenDetails)
291
- token_object.token
292
- else
293
- token_object
294
- end
297
+ # When a client has authenticated with Ably and the client is either anonymous (cannot assume a +client_id+)
298
+ # or has an assigned +client_id+ (implicit in all operations), then this client has a validated +client_id+, even
299
+ # if that client_id is +nil+ (anonymous)
300
+ #
301
+ # Once validated by Ably, the client library will enforce the use of the +client_id+ identity provided by Ably, rejecting
302
+ # messages with an invalid +client_id+ immediately
303
+ #
304
+ # @return [Boolean]
305
+ def client_id_validated?
306
+ !!@client_id_validated
295
307
  end
296
308
 
297
309
  # Auth header string used in HTTP requests to Ably
@@ -327,7 +339,7 @@ module Ably
327
339
  #
328
340
  # @return [Boolean]
329
341
  def token_renewable?
330
- token_creatable_externally? || (api_key_present? && !token)
342
+ token_creatable_externally? || (api_key_present? && !token_option)
331
343
  end
332
344
 
333
345
  # Returns false when attempting to send an API Key over a non-secure connection
@@ -338,8 +350,59 @@ module Ably
338
350
  client.use_tls? || using_token_auth?
339
351
  end
340
352
 
353
+ # True if token provided client_id is compatible with the client's configured +client_id+, when applicable
354
+ #
355
+ # @return [Boolean]
356
+ # @api private
357
+ def token_client_id_allowed?(token_client_id)
358
+ return true if client_id.nil? # no explicit client_id specified for this client
359
+ return true if client_id == '*' || token_client_id == '*' # wildcard supported always
360
+ token_client_id == client_id
361
+ end
362
+
363
+ # True if assumed_client_id is compatible with the client's configured or Ably assigned +client_id+
364
+ #
365
+ # @return [Boolean]
366
+ # @api private
367
+ def can_assume_client_id?(assumed_client_id)
368
+ if client_id_validated?
369
+ client_id == '*' || (client_id == assumed_client_id)
370
+ elsif !options[:client_id] || options[:client_id] == '*'
371
+ true # client ID is unknown
372
+ else
373
+ options[:client_id] == assumed_client_id
374
+ end
375
+ end
376
+
377
+ # Configures the client ID for this client
378
+ # Typically this occurs following an Auth or receiving a {Ably::Models::ProtocolMessage} with a +client_id+ in the {Ably::Models::ConnectionDetails}
379
+ #
380
+ # @api private
381
+ def configure_client_id(new_client_id)
382
+ # If new client ID from Ably is a wildcard, but preconfigured clientId is set, then keep the existing clientId
383
+ if has_client_id? && new_client_id == '*'
384
+ @client_id_validated = true
385
+ return
386
+ end
387
+
388
+ # If client_id is defined and not a wildcard, prevent it changing, this is not supported
389
+ if client_id && client_id != '*' && new_client_id != client_id
390
+ raise Ably::Exceptions::IncompatibleClientId.new("Client ID is immutable once configured for a client. Client ID cannot be changed to '#{new_client_id}'", 400, 40012)
391
+ end
392
+ @client_id_validated = true
393
+ @client_id = new_client_id
394
+ end
395
+
396
+ # True when a client_id other than a wildcard is configured for Auth
397
+ #
398
+ # @api private
399
+ def has_client_id?
400
+ client_id && (client_id != '*')
401
+ end
402
+
341
403
  private
342
404
  attr_reader :client
405
+ attr_reader :token_option
343
406
 
344
407
  def ensure_valid_auth_attributes(attributes)
345
408
  if attributes[:timestamp]
@@ -401,17 +464,21 @@ module Ably
401
464
 
402
465
  # Returns the current token if it exists or authorises and retrieves a token
403
466
  def token_auth_string
404
- # If a TokenDetails object has been issued by this library
405
- # then that Token will take precedence
406
- if @current_token_details
407
- authorise.token
408
- elsif token # token string was configured in the options
409
- token
467
+ if !current_token_details && token_option
468
+ # A TokenRequest was configured in the ClientOptions +:token field+ and no current token exists
469
+ # Note: If a Token or TokenDetails is provided in the initializer, the token is stored in +current_token_details+
470
+ authorise_with_token send_token_request(token_option)
471
+ current_token_details.token
410
472
  else
473
+ # Authorise will use the current token if one exists and is not expired, otherwise a new token will be issued
411
474
  authorise.token
412
475
  end
413
476
  end
414
477
 
478
+ def configure_current_token_details(token_details)
479
+ @current_token_details = token_details
480
+ end
481
+
415
482
  # Token Auth HTTP Authorization header value
416
483
  def token_auth_header
417
484
  "Bearer #{encode64(token_auth_string)}"
@@ -455,15 +522,20 @@ module Ably
455
522
  # Retrieve a token request from a specified URL, expects a JSON response
456
523
  #
457
524
  # @return [Hash]
458
- def token_request_from_auth_url(auth_url, auth_options)
525
+ def token_request_from_auth_url(auth_url, auth_options, token_params)
459
526
  uri = URI.parse(auth_url)
460
527
  connection = Faraday.new("#{uri.scheme}://#{uri.host}", connection_options)
461
- method = auth_options[:auth_method] || :get
528
+ method = auth_options[:auth_method] || options[:auth_method] || :get
529
+ params = (auth_options[:auth_params] || options[:auth_method] || {}).merge(token_params)
462
530
 
463
531
  response = connection.send(method) do |request|
464
532
  request.url uri.path
465
- request.params = CGI.parse(uri.query || '').merge(auth_options[:auth_params] || {})
466
533
  request.headers = auth_options[:auth_headers] || {}
534
+ if method.to_s.downcase == 'post'
535
+ request.body = params
536
+ else
537
+ request.params = (Addressable::URI.parse(uri.to_s).query_values || {}).merge(params)
538
+ end
467
539
  end
468
540
 
469
541
  if !response.body.kind_of?(Hash) && !response.headers['Content-Type'].to_s.match(%r{text/plain}i)
@@ -474,6 +546,42 @@ module Ably
474
546
  response.body
475
547
  end
476
548
 
549
+ # Use the provided token to authenticate immediately and store the token details in +current_token_details+
550
+ def authorise_with_token(new_token_details)
551
+ if new_token_details && !new_token_details.from_token_string?
552
+ if !token_client_id_allowed?(new_token_details.client_id)
553
+ raise Ably::Exceptions::IncompatibleClientId.new("Client ID '#{new_token_details.client_id}' in the token is incompatible with the current client ID '#{client_id}'", 400, 40012)
554
+ end
555
+ configure_client_id new_token_details.client_id
556
+ end
557
+ configure_current_token_details new_token_details
558
+ end
559
+
560
+ # Returns a TokenDetails object if the provided token_details_obj argument is a TokenDetails object, Token String
561
+ # or TokenDetails JSON object.
562
+ # If the token_details_obj is not a Token or TokenDetails +nil+ is returned
563
+ def convert_to_token_details(token_details_obj)
564
+ case token_details_obj
565
+ when Ably::Models::TokenDetails
566
+ return token_details_obj
567
+ when Hash
568
+ return Ably::Models::TokenDetails.new(token_details_obj) if IdiomaticRubyWrapper(token_details_obj).has_key?(:issued)
569
+ when String
570
+ return Ably::Models::TokenDetails.new(token: token_details_obj)
571
+ end
572
+ end
573
+
574
+ # @return [Ably::Models::TokenDetails]
575
+ def send_token_request(token_request)
576
+ token_request = Ably::Models::TokenRequest(token_request)
577
+
578
+ response = client.post("/keys/#{token_request.key_name}/requestToken",
579
+ token_request.hash, send_auth_header: false,
580
+ disable_automatic_reauthorise: true)
581
+
582
+ Ably::Models::TokenDetails.new(response.body)
583
+ end
584
+
477
585
  # Return a Hash of connection options to initiate the Faraday::Connection with
478
586
  #
479
587
  # @return [Hash]
@@ -501,7 +609,7 @@ module Ably
501
609
  # Raise exceptions if response code is invalid
502
610
  builder.use Ably::Rest::Middleware::ExternalExceptions
503
611
 
504
- setup_incoming_middleware builder, client.logger
612
+ setup_incoming_middleware builder, logger
505
613
 
506
614
  # Set Faraday's HTTP adapter
507
615
  builder.adapter Faraday.default_adapter
@@ -520,12 +628,12 @@ module Ably
520
628
  auth_callback_present? || token_url_present?
521
629
  end
522
630
 
523
- def has_client_id?
524
- !!client_id
525
- end
526
-
527
631
  def api_key_present?
528
632
  key_name && key_secret
529
633
  end
634
+
635
+ def logger
636
+ client.logger
637
+ end
530
638
  end
531
639
  end