pusher 0.14.4 → 0.14.5

Sign up to get free protection for your applications and to get access to all the features.
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