pusher 0.17.0 → 2.0.3
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 +5 -5
- data/CHANGELOG.md +112 -38
- data/README.md +134 -64
- data/lib/pusher/channel.rb +26 -10
- data/lib/pusher/client.rb +170 -63
- data/lib/pusher/request.rb +6 -2
- data/lib/pusher/version.rb +3 -0
- data/lib/pusher/webhook.rb +2 -2
- data/lib/pusher.rb +18 -10
- metadata +59 -43
- data/.document +0 -5
- data/.gemtest +0 -0
- data/.gitignore +0 -24
- data/.travis.yml +0 -19
- data/Gemfile +0 -2
- data/Rakefile +0 -11
- data/examples/async_message.rb +0 -28
- data/pusher.gemspec +0 -31
- data/spec/channel_spec.rb +0 -168
- data/spec/client_spec.rb +0 -488
- data/spec/spec_helper.rb +0 -26
- data/spec/web_hook_spec.rb +0 -117
data/spec/client_spec.rb
DELETED
@@ -1,488 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'em-http'
|
4
|
-
|
5
|
-
describe Pusher do
|
6
|
-
# The behaviour should be the same when using the Client object, or the
|
7
|
-
# 'global' client delegated through the Pusher class
|
8
|
-
[lambda { Pusher }, lambda { Pusher::Client.new }].each do |client_gen|
|
9
|
-
before :each do
|
10
|
-
@client = client_gen.call
|
11
|
-
end
|
12
|
-
|
13
|
-
describe 'default configuration' do
|
14
|
-
it 'should be preconfigured for api host' do
|
15
|
-
expect(@client.host).to eq('api.pusherapp.com')
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should be preconfigured for port 80' do
|
19
|
-
expect(@client.port).to eq(80)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should use standard logger if no other logger if defined' do
|
23
|
-
Pusher.logger.debug('foo')
|
24
|
-
expect(Pusher.logger).to be_kind_of(Logger)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe 'logging configuration' do
|
29
|
-
it "can be configured to use any logger" do
|
30
|
-
logger = double("ALogger")
|
31
|
-
expect(logger).to receive(:debug).with('foo')
|
32
|
-
Pusher.logger = logger
|
33
|
-
Pusher.logger.debug('foo')
|
34
|
-
Pusher.logger = nil
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "configuration using url" do
|
39
|
-
it "should be possible to configure everything by setting the url" do
|
40
|
-
@client.url = "test://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
41
|
-
|
42
|
-
expect(@client.scheme).to eq('test')
|
43
|
-
expect(@client.host).to eq('api.staging.pusherapp.com')
|
44
|
-
expect(@client.port).to eq(8080)
|
45
|
-
expect(@client.key).to eq('somekey')
|
46
|
-
expect(@client.secret).to eq('somesecret')
|
47
|
-
expect(@client.app_id).to eq('87')
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should override scheme and port when setting encrypted=true after url" do
|
51
|
-
@client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
52
|
-
@client.encrypted = true
|
53
|
-
|
54
|
-
expect(@client.scheme).to eq('https')
|
55
|
-
expect(@client.port).to eq(443)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should fail on bad urls" do
|
59
|
-
expect { @client.url = "gopher/somekey:somesecret@://api.staging.pusherapp.co://m:8080\apps\87" }.to raise_error(URI::InvalidURIError)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe 'configuring the cluster' do
|
64
|
-
it 'should set a new default host' do
|
65
|
-
@client.cluster = 'eu'
|
66
|
-
expect(@client.host).to eq('api-eu.pusher.com')
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'should be overridden by host if it comes after' do
|
70
|
-
@client.cluster = 'eu'
|
71
|
-
@client.host = 'api.staging.pusher.com'
|
72
|
-
expect(@client.host).to eq('api.staging.pusher.com')
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'should be overridden by url if it comes after' do
|
76
|
-
@client.cluster = 'eu'
|
77
|
-
@client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
78
|
-
|
79
|
-
expect(@client.host).to eq('api.staging.pusherapp.com')
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'should get override the url configuration if it comes after' do
|
83
|
-
@client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
84
|
-
@client.cluster = 'eu'
|
85
|
-
expect(@client.host).to eq('api-eu.pusher.com')
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'should overrie by the host configuration if it comes after' do
|
89
|
-
@client.host = 'api.staging.pusher.com'
|
90
|
-
@client.cluster = 'eu'
|
91
|
-
expect(@client.host).to eq('api-eu.pusher.com')
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe 'configuring a http proxy' do
|
96
|
-
it "should be possible to configure everything by setting the http_proxy" do
|
97
|
-
@client.http_proxy = 'http://someuser:somepassword@proxy.host.com:8080'
|
98
|
-
|
99
|
-
expect(@client.proxy).to eq({:scheme => 'http', :host => 'proxy.host.com', :port => 8080, :user => 'someuser', :password => 'somepassword'})
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe 'when configured' do
|
104
|
-
before :each do
|
105
|
-
@client.app_id = '20'
|
106
|
-
@client.key = '12345678900000001'
|
107
|
-
@client.secret = '12345678900000001'
|
108
|
-
end
|
109
|
-
|
110
|
-
describe '#[]' do
|
111
|
-
before do
|
112
|
-
@channel = @client['test_channel']
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'should return a channel' do
|
116
|
-
expect(@channel).to be_kind_of(Pusher::Channel)
|
117
|
-
end
|
118
|
-
|
119
|
-
%w{app_id key secret}.each do |config|
|
120
|
-
it "should raise exception if #{config} not configured" do
|
121
|
-
@client.send("#{config}=", nil)
|
122
|
-
expect {
|
123
|
-
@client['test_channel']
|
124
|
-
}.to raise_error(Pusher::ConfigurationError)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe '#channels' do
|
130
|
-
it "should call the correct URL and symbolise response correctly" do
|
131
|
-
api_path = %r{/apps/20/channels}
|
132
|
-
stub_request(:get, api_path).to_return({
|
133
|
-
:status => 200,
|
134
|
-
:body => MultiJson.encode('channels' => {
|
135
|
-
"channel1" => {},
|
136
|
-
"channel2" => {}
|
137
|
-
})
|
138
|
-
})
|
139
|
-
expect(@client.channels).to eq({
|
140
|
-
:channels => {
|
141
|
-
"channel1" => {},
|
142
|
-
"channel2" => {}
|
143
|
-
}
|
144
|
-
})
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
describe '#channel_info' do
|
149
|
-
it "should call correct URL and symbolise response" do
|
150
|
-
api_path = %r{/apps/20/channels/mychannel}
|
151
|
-
stub_request(:get, api_path).to_return({
|
152
|
-
:status => 200,
|
153
|
-
:body => MultiJson.encode({
|
154
|
-
'occupied' => false,
|
155
|
-
})
|
156
|
-
})
|
157
|
-
expect(@client.channel_info('mychannel')).to eq({
|
158
|
-
:occupied => false,
|
159
|
-
})
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
describe '#channel_users' do
|
164
|
-
it "should call correct URL and symbolise response" do
|
165
|
-
api_path = %r{/apps/20/channels/mychannel/users}
|
166
|
-
stub_request(:get, api_path).to_return({
|
167
|
-
:status => 200,
|
168
|
-
:body => MultiJson.encode({
|
169
|
-
'users' => [{ 'id' => 1 }]
|
170
|
-
})
|
171
|
-
})
|
172
|
-
expect(@client.channel_users('mychannel')).to eq({
|
173
|
-
:users => [{ 'id' => 1}]
|
174
|
-
})
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
describe '#authenticate' do
|
179
|
-
before :each do
|
180
|
-
@custom_data = {:uid => 123, :info => {:name => 'Foo'}}
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'should return a hash with signature including custom data and data as json string' do
|
184
|
-
allow(MultiJson).to receive(:encode).with(@custom_data).and_return 'a json string'
|
185
|
-
|
186
|
-
response = @client.authenticate('test_channel', '1.1', @custom_data)
|
187
|
-
|
188
|
-
expect(response).to eq({
|
189
|
-
:auth => "12345678900000001:#{hmac(@client.secret, "1.1:test_channel:a json string")}",
|
190
|
-
:channel_data => 'a json string'
|
191
|
-
})
|
192
|
-
end
|
193
|
-
|
194
|
-
end
|
195
|
-
|
196
|
-
describe '#trigger' do
|
197
|
-
before :each do
|
198
|
-
@api_path = %r{/apps/20/events}
|
199
|
-
stub_request(:post, @api_path).to_return({
|
200
|
-
:status => 200,
|
201
|
-
:body => MultiJson.encode({})
|
202
|
-
})
|
203
|
-
end
|
204
|
-
|
205
|
-
it "should call correct URL" do
|
206
|
-
expect(@client.trigger(['mychannel'], 'event', {'some' => 'data'})).
|
207
|
-
to eq({})
|
208
|
-
end
|
209
|
-
|
210
|
-
it "should not allow too many channels" do
|
211
|
-
expect {
|
212
|
-
@client.trigger((0..11).map{|i| 'mychannel#{i}'},
|
213
|
-
'event', {'some' => 'data'}, {
|
214
|
-
:socket_id => "12.34"
|
215
|
-
})}.to raise_error(Pusher::Error)
|
216
|
-
end
|
217
|
-
|
218
|
-
it "should pass any parameters in the body of the request" do
|
219
|
-
@client.trigger(['mychannel', 'c2'], 'event', {'some' => 'data'}, {
|
220
|
-
:socket_id => "12.34"
|
221
|
-
})
|
222
|
-
expect(WebMock).to have_requested(:post, @api_path).with { |req|
|
223
|
-
parsed = MultiJson.decode(req.body)
|
224
|
-
expect(parsed["name"]).to eq('event')
|
225
|
-
expect(parsed["channels"]).to eq(["mychannel", "c2"])
|
226
|
-
expect(parsed["socket_id"]).to eq('12.34')
|
227
|
-
}
|
228
|
-
end
|
229
|
-
|
230
|
-
it "should convert non string data to JSON before posting" do
|
231
|
-
@client.trigger(['mychannel'], 'event', {'some' => 'data'})
|
232
|
-
expect(WebMock).to have_requested(:post, @api_path).with { |req|
|
233
|
-
expect(MultiJson.decode(req.body)["data"]).to eq('{"some":"data"}')
|
234
|
-
}
|
235
|
-
end
|
236
|
-
|
237
|
-
it "should accept a single channel as well as an array" do
|
238
|
-
@client.trigger('mychannel', 'event', {'some' => 'data'})
|
239
|
-
expect(WebMock).to have_requested(:post, @api_path).with { |req|
|
240
|
-
expect(MultiJson.decode(req.body)["channels"]).to eq(['mychannel'])
|
241
|
-
}
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
describe '#trigger_async' do
|
246
|
-
before :each do
|
247
|
-
@api_path = %r{/apps/20/events}
|
248
|
-
stub_request(:post, @api_path).to_return({
|
249
|
-
:status => 200,
|
250
|
-
:body => MultiJson.encode({})
|
251
|
-
})
|
252
|
-
end
|
253
|
-
|
254
|
-
it "should call correct URL" do
|
255
|
-
EM.run {
|
256
|
-
@client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback { |r|
|
257
|
-
expect(r).to eq({})
|
258
|
-
EM.stop
|
259
|
-
}
|
260
|
-
}
|
261
|
-
end
|
262
|
-
|
263
|
-
it "should pass any parameters in the body of the request" do
|
264
|
-
EM.run {
|
265
|
-
@client.trigger_async('mychannel', 'event', {'some' => 'data'}, {
|
266
|
-
:socket_id => "12.34"
|
267
|
-
}).callback {
|
268
|
-
expect(WebMock).to have_requested(:post, @api_path).with { |req|
|
269
|
-
expect(MultiJson.decode(req.body)["socket_id"]).to eq('12.34')
|
270
|
-
}
|
271
|
-
EM.stop
|
272
|
-
}
|
273
|
-
}
|
274
|
-
end
|
275
|
-
|
276
|
-
it "should convert non string data to JSON before posting" do
|
277
|
-
EM.run {
|
278
|
-
@client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback {
|
279
|
-
expect(WebMock).to have_requested(:post, @api_path).with { |req|
|
280
|
-
expect(MultiJson.decode(req.body)["data"]).to eq('{"some":"data"}')
|
281
|
-
}
|
282
|
-
EM.stop
|
283
|
-
}
|
284
|
-
}
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
[:get, :post].each do |verb|
|
289
|
-
describe "##{verb}" do
|
290
|
-
before :each do
|
291
|
-
@url_regexp = %r{api.pusherapp.com}
|
292
|
-
stub_request(verb, @url_regexp).
|
293
|
-
to_return(:status => 200, :body => "{}")
|
294
|
-
end
|
295
|
-
|
296
|
-
let(:call_api) { @client.send(verb, '/path') }
|
297
|
-
|
298
|
-
it "should use http by default" do
|
299
|
-
call_api
|
300
|
-
expect(WebMock).to have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
301
|
-
end
|
302
|
-
|
303
|
-
it "should use https if configured" do
|
304
|
-
@client.encrypted = true
|
305
|
-
call_api
|
306
|
-
expect(WebMock).to have_requested(verb, %r{https://api.pusherapp.com})
|
307
|
-
end
|
308
|
-
|
309
|
-
it "should format the respose hash with symbols at first level" do
|
310
|
-
stub_request(verb, @url_regexp).to_return({
|
311
|
-
:status => 200,
|
312
|
-
:body => MultiJson.encode({'something' => {'a' => 'hash'}})
|
313
|
-
})
|
314
|
-
expect(call_api).to eq({
|
315
|
-
:something => {'a' => 'hash'}
|
316
|
-
})
|
317
|
-
end
|
318
|
-
|
319
|
-
it "should catch all http exceptions and raise a Pusher::HTTPError wrapping the original error" do
|
320
|
-
stub_request(verb, @url_regexp).to_raise(HTTPClient::TimeoutError)
|
321
|
-
|
322
|
-
error = nil
|
323
|
-
begin
|
324
|
-
call_api
|
325
|
-
rescue => e
|
326
|
-
error = e
|
327
|
-
end
|
328
|
-
|
329
|
-
expect(error.class).to eq(Pusher::HTTPError)
|
330
|
-
expect(error).to be_kind_of(Pusher::Error)
|
331
|
-
expect(error.message).to eq('Exception from WebMock (HTTPClient::TimeoutError)')
|
332
|
-
expect(error.original_error.class).to eq(HTTPClient::TimeoutError)
|
333
|
-
end
|
334
|
-
|
335
|
-
it "should raise Pusher::Error if call returns 400" do
|
336
|
-
stub_request(verb, @url_regexp).to_return({:status => 400})
|
337
|
-
expect { call_api }.to raise_error(Pusher::Error)
|
338
|
-
end
|
339
|
-
|
340
|
-
it "should raise AuthenticationError if pusher returns 401" do
|
341
|
-
stub_request(verb, @url_regexp).to_return({:status => 401})
|
342
|
-
expect { call_api }.to raise_error(Pusher::AuthenticationError)
|
343
|
-
end
|
344
|
-
|
345
|
-
it "should raise Pusher::Error if pusher returns 404" do
|
346
|
-
stub_request(verb, @url_regexp).to_return({:status => 404})
|
347
|
-
expect { call_api }.to raise_error(Pusher::Error, '404 Not found (/apps/20/path)')
|
348
|
-
end
|
349
|
-
|
350
|
-
it "should raise Pusher::Error if pusher returns 407" do
|
351
|
-
stub_request(verb, @url_regexp).to_return({:status => 407})
|
352
|
-
expect { call_api }.to raise_error(Pusher::Error, 'Proxy Authentication Required')
|
353
|
-
end
|
354
|
-
|
355
|
-
it "should raise Pusher::Error if pusher returns 500" do
|
356
|
-
stub_request(verb, @url_regexp).to_return({:status => 500, :body => "some error"})
|
357
|
-
expect { call_api }.to raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
361
|
-
|
362
|
-
describe "async calling without eventmachine" do
|
363
|
-
[[:get, :get_async], [:post, :post_async]].each do |verb, method|
|
364
|
-
describe "##{method}" do
|
365
|
-
before :each do
|
366
|
-
@url_regexp = %r{api.pusherapp.com}
|
367
|
-
stub_request(verb, @url_regexp).
|
368
|
-
to_return(:status => 200, :body => "{}")
|
369
|
-
end
|
370
|
-
|
371
|
-
let(:call_api) {
|
372
|
-
@client.send(method, '/path').tap { |c|
|
373
|
-
# Allow the async thread (inside httpclient) to run
|
374
|
-
while !c.finished?
|
375
|
-
sleep 0.01
|
376
|
-
end
|
377
|
-
}
|
378
|
-
}
|
379
|
-
|
380
|
-
it "should use http by default" do
|
381
|
-
call_api
|
382
|
-
expect(WebMock).to have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
383
|
-
end
|
384
|
-
|
385
|
-
it "should use https if configured" do
|
386
|
-
@client.encrypted = true
|
387
|
-
call_api
|
388
|
-
expect(WebMock).to have_requested(verb, %r{https://api.pusherapp.com})
|
389
|
-
end
|
390
|
-
|
391
|
-
# Note that the raw httpclient connection object is returned and
|
392
|
-
# the response isn't handled (by handle_response) in the normal way.
|
393
|
-
it "should return a httpclient connection object" do
|
394
|
-
connection = call_api
|
395
|
-
expect(connection.finished?).to be_truthy
|
396
|
-
response = connection.pop
|
397
|
-
expect(response.status).to eq(200)
|
398
|
-
expect(response.body.read).to eq("{}")
|
399
|
-
end
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
describe "async calling with eventmachine" do
|
405
|
-
[[:get, :get_async], [:post, :post_async]].each do |verb, method|
|
406
|
-
describe "##{method}" do
|
407
|
-
before :each do
|
408
|
-
@url_regexp = %r{api.pusherapp.com}
|
409
|
-
stub_request(verb, @url_regexp).
|
410
|
-
to_return(:status => 200, :body => "{}")
|
411
|
-
end
|
412
|
-
|
413
|
-
let(:call_api) { @client.send(method, '/path') }
|
414
|
-
|
415
|
-
it "should use http by default" do
|
416
|
-
EM.run {
|
417
|
-
call_api.callback {
|
418
|
-
expect(WebMock).to have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
419
|
-
EM.stop
|
420
|
-
}
|
421
|
-
}
|
422
|
-
end
|
423
|
-
|
424
|
-
it "should use https if configured" do
|
425
|
-
EM.run {
|
426
|
-
@client.encrypted = true
|
427
|
-
call_api.callback {
|
428
|
-
expect(WebMock).to have_requested(verb, %r{https://api.pusherapp.com})
|
429
|
-
EM.stop
|
430
|
-
}
|
431
|
-
}
|
432
|
-
end
|
433
|
-
|
434
|
-
it "should format the respose hash with symbols at first level" do
|
435
|
-
EM.run {
|
436
|
-
stub_request(verb, @url_regexp).to_return({
|
437
|
-
:status => 200,
|
438
|
-
:body => MultiJson.encode({'something' => {'a' => 'hash'}})
|
439
|
-
})
|
440
|
-
call_api.callback { |response|
|
441
|
-
expect(response).to eq({
|
442
|
-
:something => {'a' => 'hash'}
|
443
|
-
})
|
444
|
-
EM.stop
|
445
|
-
}
|
446
|
-
}
|
447
|
-
end
|
448
|
-
|
449
|
-
it "should errback with Pusher::Error on unsuccessful response" do
|
450
|
-
EM.run {
|
451
|
-
stub_request(verb, @url_regexp).to_return({:status => 400})
|
452
|
-
|
453
|
-
call_api.errback { |e|
|
454
|
-
expect(e.class).to eq(Pusher::Error)
|
455
|
-
EM.stop
|
456
|
-
}.callback {
|
457
|
-
fail
|
458
|
-
}
|
459
|
-
}
|
460
|
-
end
|
461
|
-
end
|
462
|
-
end
|
463
|
-
end
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
describe 'configuring cluster' do
|
468
|
-
it 'should allow clients to specify the cluster only with the default host' do
|
469
|
-
client = Pusher::Client.new({
|
470
|
-
:scheme => 'http',
|
471
|
-
:cluster => 'eu',
|
472
|
-
:port => 80
|
473
|
-
})
|
474
|
-
expect(client.host).to eq('api-eu.pusher.com')
|
475
|
-
end
|
476
|
-
|
477
|
-
it 'should always have host override any supplied cluster value' do
|
478
|
-
client = Pusher::Client.new({
|
479
|
-
:scheme => 'http',
|
480
|
-
:host => 'api.staging.pusherapp.com',
|
481
|
-
:cluster => 'eu',
|
482
|
-
:port => 80
|
483
|
-
})
|
484
|
-
expect(client.host).to eq('api.staging.pusherapp.com')
|
485
|
-
end
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
data/spec/spec_helper.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'bundler/setup'
|
3
|
-
rescue LoadError
|
4
|
-
puts 'although not required, it is recommended that you use bundler when running the tests'
|
5
|
-
end
|
6
|
-
|
7
|
-
ENV['PUSHER_URL']= 'http://some:secret@api.secret.pusherapp.com:441/apps/54'
|
8
|
-
|
9
|
-
require 'rspec'
|
10
|
-
require 'em-http' # As of webmock 1.4.0, em-http must be loaded first
|
11
|
-
require 'webmock/rspec'
|
12
|
-
|
13
|
-
require 'pusher'
|
14
|
-
require 'eventmachine'
|
15
|
-
|
16
|
-
RSpec.configure do |config|
|
17
|
-
config.before(:each) do
|
18
|
-
WebMock.reset!
|
19
|
-
WebMock.disable_net_connect!
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def hmac(key, data)
|
24
|
-
digest = OpenSSL::Digest::SHA256.new
|
25
|
-
OpenSSL::HMAC.hexdigest(digest, key, data)
|
26
|
-
end
|
data/spec/web_hook_spec.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'rack'
|
4
|
-
require 'stringio'
|
5
|
-
|
6
|
-
describe Pusher::WebHook do
|
7
|
-
before :each do
|
8
|
-
@hook_data = {
|
9
|
-
"time_ms" => 123456,
|
10
|
-
"events" => [
|
11
|
-
{"name" => 'foo'}
|
12
|
-
]
|
13
|
-
}
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "initialization" do
|
17
|
-
it "can be initialized with Rack::Request" do
|
18
|
-
request = Rack::Request.new({
|
19
|
-
'HTTP_X_PUSHER_KEY' => '1234',
|
20
|
-
'HTTP_X_PUSHER_SIGNATURE' => 'asdf',
|
21
|
-
'CONTENT_TYPE' => 'application/json',
|
22
|
-
'rack.input' => StringIO.new(MultiJson.encode(@hook_data))
|
23
|
-
})
|
24
|
-
wh = Pusher::WebHook.new(request)
|
25
|
-
expect(wh.key).to eq('1234')
|
26
|
-
expect(wh.signature).to eq('asdf')
|
27
|
-
expect(wh.data).to eq(@hook_data)
|
28
|
-
end
|
29
|
-
|
30
|
-
it "can be initialized with a hash" do
|
31
|
-
request = {
|
32
|
-
:key => '1234',
|
33
|
-
:signature => 'asdf',
|
34
|
-
:content_type => 'application/json',
|
35
|
-
:body => MultiJson.encode(@hook_data),
|
36
|
-
}
|
37
|
-
wh = Pusher::WebHook.new(request)
|
38
|
-
expect(wh.key).to eq('1234')
|
39
|
-
expect(wh.signature).to eq('asdf')
|
40
|
-
expect(wh.data).to eq(@hook_data)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "after initialization" do
|
45
|
-
before :each do
|
46
|
-
@body = MultiJson.encode(@hook_data)
|
47
|
-
request = {
|
48
|
-
:key => '1234',
|
49
|
-
:signature => hmac('asdf', @body),
|
50
|
-
:content_type => 'application/json',
|
51
|
-
:body => @body
|
52
|
-
}
|
53
|
-
|
54
|
-
@client = Pusher::Client.new
|
55
|
-
@wh = Pusher::WebHook.new(request, @client)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should validate" do
|
59
|
-
@client.key = '1234'
|
60
|
-
@client.secret = 'asdf'
|
61
|
-
expect(@wh).to be_valid
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should not validate if key is wrong" do
|
65
|
-
@client.key = '12345'
|
66
|
-
@client.secret = 'asdf'
|
67
|
-
expect(Pusher.logger).to receive(:warn).with("Received webhook with unknown key: 1234")
|
68
|
-
expect(@wh).not_to be_valid
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should not validate if secret is wrong" do
|
72
|
-
@client.key = '1234'
|
73
|
-
@client.secret = 'asdfxxx'
|
74
|
-
digest = OpenSSL::Digest::SHA256.new
|
75
|
-
expected = OpenSSL::HMAC.hexdigest(digest, @client.secret, @body)
|
76
|
-
expect(Pusher.logger).to receive(:warn).with("Received WebHook with invalid signature: got #{@wh.signature}, expected #{expected}")
|
77
|
-
expect(@wh).not_to be_valid
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should validate with an extra token" do
|
81
|
-
@client.key = '12345'
|
82
|
-
@client.secret = 'xxx'
|
83
|
-
expect(@wh.valid?({:key => '1234', :secret => 'asdf'})).to be_truthy
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should validate with an array of extra tokens" do
|
87
|
-
@client.key = '123456'
|
88
|
-
@client.secret = 'xxx'
|
89
|
-
expect(@wh.valid?([
|
90
|
-
{:key => '12345', :secret => 'wtf'},
|
91
|
-
{:key => '1234', :secret => 'asdf'}
|
92
|
-
])).to be_truthy
|
93
|
-
end
|
94
|
-
|
95
|
-
it "should not validate if all keys are wrong with extra tokens" do
|
96
|
-
@client.key = '123456'
|
97
|
-
@client.secret = 'asdf'
|
98
|
-
expect(Pusher.logger).to receive(:warn).with("Received webhook with unknown key: 1234")
|
99
|
-
expect(@wh.valid?({:key => '12345', :secret => 'asdf'})).to be_falsey
|
100
|
-
end
|
101
|
-
|
102
|
-
it "should not validate if secret is wrong with extra tokens" do
|
103
|
-
@client.key = '123456'
|
104
|
-
@client.secret = 'asdfxxx'
|
105
|
-
expect(Pusher.logger).to receive(:warn).with(/Received WebHook with invalid signature/)
|
106
|
-
expect(@wh.valid?({:key => '1234', :secret => 'wtf'})).to be_falsey
|
107
|
-
end
|
108
|
-
|
109
|
-
it "should expose events" do
|
110
|
-
expect(@wh.events).to eq(@hook_data["events"])
|
111
|
-
end
|
112
|
-
|
113
|
-
it "should expose time" do
|
114
|
-
expect(@wh.time).to eq(Time.at(123.456))
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|