pusher 0.14.4 → 0.14.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b01f88da67dca16b39dbf8294f56a38d9737e13
4
- data.tar.gz: 56b1a23bc74b234a487319a22138323463f0271e
3
+ metadata.gz: 9bd67ccabffeb24e369e09b592b06a9991c4795d
4
+ data.tar.gz: 035e6c2def599b1ce8a6cd12897a908a011fc1fa
5
5
  SHA512:
6
- metadata.gz: 8c95993afb1e953a5c6b0ea21e3ee26db91c0b89ba7e77bbb41965304dc81ed77810eafdffefc0da92347f977e374a710d5a0baa2e1f17c827eebd7d5540210f
7
- data.tar.gz: a730e0e7f0285d0b522a5fb42e903a6ef42aee479037269f742b4a56d132392664220d6aca748cb840b32f9476f000fee782dd6c752dc0b1a3db959cfdc4b78c
6
+ metadata.gz: da4f65dc4b9cbd5d37020d26bde929381413b3285346f5a9979d664967fc1a1a606ee84572dd1acf8bd9fb70aa5626f996383aa20ff91949dc6120242c35e8bc
7
+ data.tar.gz: 63ddd45053e53489dcc2759eabf4ae76b7732cc37fb0ad72866716aba87473971702f43d036fffde82d220abf87890b83395c2e09ce07c52c67f414173fcab35
@@ -1,12 +1,12 @@
1
1
  language: ruby
2
-
2
+ sudo: false
3
3
  rvm:
4
4
  - 1.8.7
5
5
  - 1.9.2
6
6
  - 1.9.3
7
7
  - 2.0.0
8
- - 2.1.1
9
- - 2.1.2
8
+ - 2.1
9
+ - 2.2
10
10
  - jruby-18mode
11
11
  - jruby-19mode
12
12
  - rbx-2
@@ -1,4 +1,9 @@
1
1
 
2
+ 0.14.5 / 2015-05-11
3
+ ==================
4
+
5
+ * SECURITY: Prevent auth delegation trough crafted socket IDs
6
+
2
7
  0.14.4 / 2015-01-20
3
8
  ==================
4
9
 
data/README.md CHANGED
@@ -1,17 +1,21 @@
1
1
  Pusher gem
2
2
  ==========
3
3
 
4
- [![Build Status](https://secure.travis-ci.org/pusher/pusher-gem.svg?branch=master)](http://travis-ci.org/pusher/pusher-gem)
4
+ [![Build Status](https://secure.travis-ci.org/pusher/pusher-http-ruby.svg?branch=master)](http://travis-ci.org/pusher/pusher-http-ruby)
5
5
 
6
6
  ## Installation & Configuration
7
7
 
8
8
  Add pusher to your Gemfile, and then run `bundle install`
9
9
 
10
- gem 'pusher'
10
+ ``` ruby
11
+ gem 'pusher'
12
+ ```
11
13
 
12
14
  or install via gem
13
15
 
14
- gem install pusher
16
+ ``` bash
17
+ gem install pusher
18
+ ```
15
19
 
16
20
  After registering at <http://pusher.com> configure your app with the security credentials.
17
21
 
@@ -19,33 +23,43 @@ After registering at <http://pusher.com> configure your app with the security cr
19
23
 
20
24
  The most standard way of configuring Pusher is to do it globally on the Pusher class.
21
25
 
22
- Pusher.app_id = 'your-pusher-app-id'
23
- Pusher.key = 'your-pusher-key'
24
- Pusher.secret = 'your-pusher-secret'
26
+ ``` ruby
27
+ Pusher.app_id = 'your-pusher-app-id'
28
+ Pusher.key = 'your-pusher-key'
29
+ Pusher.secret = 'your-pusher-secret'
30
+ ```
25
31
 
26
32
  Global configuration will automatically be set from the `PUSHER_URL` environment variable if it exists. This should be in the form `http://KEY:SECRET@api.pusherapp.com/apps/APP_ID`. On Heroku this environment variable will already be set.
27
33
 
28
34
  If you need to make requests via a HTTP proxy then it can be configured
29
35
 
30
- Pusher.http_proxy = 'http://(user):(password)@(host):(port)'
36
+ ``` ruby
37
+ Pusher.http_proxy = 'http://(user):(password)@(host):(port)'
38
+ ```
31
39
 
32
40
  By default API requests are made over HTTP. HTTPS can be used by setting
33
41
 
34
- Pusher.encrypted = true
42
+ ``` ruby
43
+ Pusher.encrypted = true
44
+ ```
35
45
 
36
46
  As of version 0.12, SSL certificates are verified when using the synchronous http client. If you need to disable this behaviour for any reason use:
37
47
 
38
- Pusher.default_client.sync_http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
48
+ ``` ruby
49
+ Pusher.default_client.sync_http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
50
+ ```
39
51
 
40
52
  ### Instantiating a Pusher client
41
53
 
42
54
  Sometimes you may have multiple sets of API keys, or want different configuration in different parts of your application. In these scenarios, a pusher `client` may be configured:
43
55
 
44
- pusher_client = Pusher::Client.new({
45
- app_id: 'your-pusher-app-id',
46
- key: 'your-pusher-key',
47
- secret: 'your-pusher-secret'
48
- })
56
+ ``` ruby
57
+ pusher_client = Pusher::Client.new({
58
+ app_id: 'your-pusher-app-id',
59
+ key: 'your-pusher-key',
60
+ secret: 'your-pusher-secret'
61
+ })
62
+ ```
49
63
 
50
64
  This `client` will have all the functionality listed on the main Pusher class (which proxies to a client internally).
51
65
 
@@ -59,34 +73,44 @@ The Pusher gem contains a number of helpers for interacting with the service. As
59
73
 
60
74
  Handle errors by rescuing `Pusher::Error` (all errors are descendants of this error)
61
75
 
62
- begin
63
- Pusher.trigger('a_channel', 'an_event', {:some => 'data'})
64
- rescue Pusher::Error => e
65
- # (Pusher::AuthenticationError, Pusher::HTTPError, or Pusher::Error)
66
- end
76
+ ``` ruby
77
+ begin
78
+ Pusher.trigger('a_channel', 'an_event', {:some => 'data'})
79
+ rescue Pusher::Error => e
80
+ # (Pusher::AuthenticationError, Pusher::HTTPError, or Pusher::Error)
81
+ end
82
+ ```
67
83
 
68
84
  ### Logging
69
85
 
70
86
  Errors are logged to `Pusher.logger`. It will by default log at info level to STDOUT using `Logger` from the standard library, however you can assign any logger:
71
87
 
72
- Pusher.logger = Rails.logger
88
+ ``` ruby
89
+ Pusher.logger = Rails.logger
90
+ ```
73
91
 
74
92
  ### Publishing events
75
93
 
76
94
  An event can be published to one or more channels (limited to 10) in one API call:
77
95
 
78
- Pusher.trigger('channel', 'event', {foo: 'bar'})
79
- Pusher.trigger(['channel_1', 'channel_2'], 'event_name', {foo: 'bar'})
96
+ ``` ruby
97
+ Pusher.trigger('channel', 'event', {foo: 'bar'})
98
+ Pusher.trigger(['channel_1', 'channel_2'], 'event_name', {foo: 'bar'})
99
+ ```
80
100
 
81
101
  An optional fourth argument may be used to send additional parameters to the API, for example to [exclude a single connection from receiving the event](http://pusher.com/docs/publisher_api_guide/publisher_excluding_recipients).
82
102
 
83
- Pusher.trigger('channel', 'event', {foo: 'bar'}, {socket_id: '123.456'})
103
+ ``` ruby
104
+ Pusher.trigger('channel', 'event', {foo: 'bar'}, {socket_id: '123.456'})
105
+ ```
84
106
 
85
107
  #### Deprecated publisher API
86
108
 
87
109
  Most examples and documentation will refer to the following syntax for triggering an event:
88
110
 
89
- Pusher['a_channel'].trigger('an_event', {:some => 'data'})
111
+ ``` ruby
112
+ Pusher['a_channel'].trigger('an_event', {:some => 'data'})
113
+ ```
90
114
 
91
115
  This will continue to work, but has been replaced by `Pusher.trigger` which supports one or multiple channels.
92
116
 
@@ -96,11 +120,13 @@ Aside from triggering events, the REST API also supports a number of operations
96
120
 
97
121
  All requests must be signed by using your secret key, which is handled automatically using these methods:
98
122
 
99
- # using the Pusher class
100
- Pusher.get('url_without_app_id', params)
123
+ ``` ruby
124
+ # using the Pusher class
125
+ Pusher.get('url_without_app_id', params)
101
126
 
102
- # using a client
103
- pusher_client.post('url_without_app_id', params)
127
+ # using a client
128
+ pusher_client.post('url_without_app_id', params)
129
+ ```
104
130
 
105
131
  Note that you don't need to specify your app_id in the URL, as this is inferred from your credentials.
106
132
 
@@ -128,11 +154,13 @@ It is of course also possible to make calls to pusher via a job queue. This appr
128
154
 
129
155
  The `_async` methods return an `EM::Deferrable` which you can bind callbacks to:
130
156
 
131
- Pusher.get_async("/channels").callback { |response|
132
- # use reponse[:channels]
133
- }.errback { |error|
134
- # error is an instance of Pusher::Error
135
- }
157
+ ``` ruby
158
+ Pusher.get_async("/channels").callback { |response|
159
+ # use reponse[:channels]
160
+ }.errback { |error|
161
+ # error is an instance of Pusher::Error
162
+ }
163
+ ```
136
164
 
137
165
  A HTTP error or an error response from pusher will cause the errback to be called with an appropriate error object.
138
166
 
@@ -149,34 +177,38 @@ It's possible to use the gem to authenticate subscription requests to private or
149
177
 
150
178
  ### Private channels
151
179
 
152
- Pusher['private-my_channel'].authenticate(params[:socket_id])
180
+ ``` ruby
181
+ Pusher['private-my_channel'].authenticate(params[:socket_id])
182
+ ```
153
183
 
154
184
  ### Presence channels
155
185
 
156
186
  These work in a very similar way, but require a unique identifier for the user being authenticated, and optionally some attributes that are provided to clients via presence events:
157
187
 
158
- Pusher['presence-my_channel'].authenticate(params[:socket_id], {
159
- user_id: 'user_id',
160
- user_info: {} # optional
161
- })
162
-
163
-
188
+ ``` ruby
189
+ Pusher['presence-my_channel'].authenticate(params[:socket_id], {
190
+ user_id: 'user_id',
191
+ user_info: {} # optional
192
+ })
193
+ ```
164
194
 
165
195
  ## Receiving WebHooks
166
196
 
167
197
  A WebHook object may be created to validate received WebHooks against your app credentials, and to extract events. It should be created with the `Rack::Request` object (available as `request` in Rails controllers or Sinatra handlers for example).
168
198
 
169
- webhook = Pusher.webhook(request)
170
- if webhook.valid?
171
- webhook.events.each do |event|
172
- case event["name"]
173
- when 'channel_occupied'
174
- puts "Channel occupied: #{event["channel"]}"
175
- when 'channel_vacated'
176
- puts "Channel vacated: #{event["channel"]}"
177
- end
178
- end
179
- render text: 'ok'
180
- else
181
- render text: 'invalid', status: 401
199
+ ``` ruby
200
+ webhook = Pusher.webhook(request)
201
+ if webhook.valid?
202
+ webhook.events.each do |event|
203
+ case event["name"]
204
+ when 'channel_occupied'
205
+ puts "Channel occupied: #{event["channel"]}"
206
+ when 'channel_vacated'
207
+ puts "Channel vacated: #{event["channel"]}"
182
208
  end
209
+ end
210
+ render text: 'ok'
211
+ else
212
+ render text: 'invalid', status: 401
213
+ end
214
+ ```
@@ -34,7 +34,10 @@ module Pusher
34
34
  #
35
35
  def trigger_async(event_name, data, socket_id = nil)
36
36
  params = {}
37
- params[:socket_id] = socket_id if socket_id
37
+ if socket_id
38
+ validate_socket_id(socket_id)
39
+ params[:socket_id] = socket_id
40
+ end
38
41
  @client.trigger_async(name, event_name, data, params)
39
42
  end
40
43
 
@@ -60,7 +63,10 @@ module Pusher
60
63
  #
61
64
  def trigger!(event_name, data, socket_id = nil)
62
65
  params = {}
63
- params[:socket_id] = socket_id if socket_id
66
+ if socket_id
67
+ validate_socket_id(socket_id)
68
+ params[:socket_id] = socket_id
69
+ end
64
70
  @client.trigger(name, event_name, data, params)
65
71
  end
66
72
 
@@ -115,9 +121,7 @@ module Pusher
115
121
  # @return [String]
116
122
  #
117
123
  def authentication_string(socket_id, custom_string = nil)
118
- if socket_id.nil? || socket_id.empty?
119
- raise Error, "Invalid socket_id #{socket_id}"
120
- end
124
+ validate_socket_id(socket_id)
121
125
 
122
126
  unless custom_string.nil? || custom_string.kind_of?(String)
123
127
  raise Error, 'Custom argument must be a string'
@@ -162,5 +166,13 @@ module Pusher
162
166
  r[:channel_data] = custom_data if custom_data
163
167
  r
164
168
  end
169
+
170
+ private
171
+
172
+ def validate_socket_id(socket_id)
173
+ unless socket_id && /\A\d+\.\d+\z/.match(socket_id)
174
+ raise Pusher::Error, "Invalid socket ID #{socket_id.inspect}"
175
+ end
176
+ end
165
177
  end
166
178
  end
@@ -3,11 +3,11 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "pusher"
6
- s.version = "0.14.4"
6
+ s.version = "0.14.5"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Pusher"]
9
9
  s.email = ["support@pusher.com"]
10
- s.homepage = "http://github.com/pusher/pusher-gem"
10
+ s.homepage = "http://github.com/pusher/pusher-http-ruby"
11
11
  s.summary = %q{Pusher API client}
12
12
  s.description = %q{Wrapper for pusher.com REST api}
13
13
  s.license = "MIT"
@@ -99,9 +99,9 @@ describe Pusher::Channel do
99
99
  end
100
100
 
101
101
  it "should return an authentication string given a socket id" do
102
- auth = @channel.authentication_string('socketid')
102
+ auth = @channel.authentication_string('1.1')
103
103
 
104
- auth.should == '12345678900000001:827076f551e22451357939e4c7bb1200de29f921d5bf80b40d71668f9cd61c40'
104
+ auth.should == '12345678900000001:02259dff9a2a3f71ea8ab29ac0c0c0ef7996c8f3fd3702be5533f30da7d7fed4'
105
105
  end
106
106
 
107
107
  it "should raise error if authentication is invalid" do
@@ -112,17 +112,17 @@ describe Pusher::Channel do
112
112
 
113
113
  describe 'with extra string argument' do
114
114
  it 'should be a string or nil' do
115
- authentication_string('socketid', 123).should raise_error Pusher::Error
116
- authentication_string('socketid', {}).should raise_error Pusher::Error
115
+ authentication_string('1.1', 123).should raise_error Pusher::Error
116
+ authentication_string('1.1', {}).should raise_error Pusher::Error
117
117
 
118
- authentication_string('socketid', 'boom').should_not raise_error
119
- authentication_string('socketid', nil).should_not raise_error
118
+ authentication_string('1.1', 'boom').should_not raise_error
119
+ authentication_string('1.1', nil).should_not raise_error
120
120
  end
121
121
 
122
122
  it "should return an authentication string given a socket id and custom args" do
123
- auth = @channel.authentication_string('socketid', 'foobar')
123
+ auth = @channel.authentication_string('1.1', 'foobar')
124
124
 
125
- auth.should == "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:foobar")}"
125
+ auth.should == "12345678900000001:#{hmac(@client.secret, "1.1:test_channel:foobar")}"
126
126
  end
127
127
  end
128
128
  end
@@ -135,12 +135,34 @@ describe Pusher::Channel do
135
135
  it 'should return a hash with signature including custom data and data as json string' do
136
136
  MultiJson.stub(:encode).with(@custom_data).and_return 'a json string'
137
137
 
138
- response = @channel.authenticate('socketid', @custom_data)
138
+ response = @channel.authenticate('1.1', @custom_data)
139
139
 
140
140
  response.should == {
141
- :auth => "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:a json string")}",
141
+ :auth => "12345678900000001:#{hmac(@client.secret, "1.1:test_channel:a json string")}",
142
142
  :channel_data => 'a json string'
143
143
  }
144
144
  end
145
+
146
+ it 'should fail on invalid socket_ids' do
147
+ lambda {
148
+ @channel.authenticate('1.1:')
149
+ }.should raise_error Pusher::Error
150
+
151
+ lambda {
152
+ @channel.authenticate('1.1foo', 'channel')
153
+ }.should raise_error Pusher::Error
154
+
155
+ lambda {
156
+ @channel.authenticate(':1.1')
157
+ }.should raise_error Pusher::Error
158
+
159
+ lambda {
160
+ @channel.authenticate('foo1.1', 'channel')
161
+ }.should raise_error Pusher::Error
162
+
163
+ lambda {
164
+ @channel.authenticate('foo', 'channel')
165
+ }.should raise_error Pusher::Error
166
+ end
145
167
  end
146
168
  end
@@ -225,19 +225,19 @@ describe Pusher do
225
225
  lambda {
226
226
  @client.trigger((0..11).map{|i| 'mychannel#{i}'},
227
227
  'event', {'some' => 'data'}, {
228
- :socket_id => "1234"
228
+ :socket_id => "12.34"
229
229
  })}.should raise_error(Pusher::Error)
230
230
  end
231
231
 
232
232
  it "should pass any parameters in the body of the request" do
233
233
  @client.trigger(['mychannel', 'c2'], 'event', {'some' => 'data'}, {
234
- :socket_id => "1234"
234
+ :socket_id => "12.34"
235
235
  })
236
236
  WebMock.should have_requested(:post, @api_path).with { |req|
237
237
  parsed = MultiJson.decode(req.body)
238
238
  parsed["name"].should == 'event'
239
239
  parsed["channels"].should == ["mychannel", "c2"]
240
- parsed["socket_id"].should == '1234'
240
+ parsed["socket_id"].should == '12.34'
241
241
  }
242
242
  end
243
243
 
@@ -277,10 +277,10 @@ describe Pusher do
277
277
  it "should pass any parameters in the body of the request" do
278
278
  EM.run {
279
279
  @client.trigger_async('mychannel', 'event', {'some' => 'data'}, {
280
- :socket_id => "1234"
280
+ :socket_id => "12.34"
281
281
  }).callback {
282
282
  WebMock.should have_requested(:post, @api_path).with { |req|
283
- MultiJson.decode(req.body)["socket_id"].should == '1234'
283
+ MultiJson.decode(req.body)["socket_id"].should == '12.34'
284
284
  }
285
285
  EM.stop
286
286
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pusher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.4
4
+ version: 0.14.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pusher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-20 00:00:00.000000000 Z
11
+ date: 2015-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -150,7 +150,7 @@ files:
150
150
  - spec/client_spec.rb
151
151
  - spec/spec_helper.rb
152
152
  - spec/web_hook_spec.rb
153
- homepage: http://github.com/pusher/pusher-gem
153
+ homepage: http://github.com/pusher/pusher-http-ruby
154
154
  licenses:
155
155
  - MIT
156
156
  metadata: {}
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
170
  version: '0'
171
171
  requirements: []
172
172
  rubyforge_project:
173
- rubygems_version: 2.4.2
173
+ rubygems_version: 2.4.6
174
174
  signing_key:
175
175
  specification_version: 4
176
176
  summary: Pusher API client