scout 5.7.1 → 5.7.2.pre
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.
- data/CHANGELOG.markdown +5 -0
- data/lib/scout/command/run.rb +1 -1
- data/lib/scout/server.rb +2 -1
- data/lib/scout/streamer.rb +3 -2
- data/lib/scout/streamer_daemon.rb +4 -4
- data/lib/scout/version.rb +1 -1
- data/test/scout_test.rb +7 -8
- data/vendor/httpclient/README.txt +759 -0
- data/vendor/httpclient/bin/httpclient +65 -0
- data/vendor/httpclient/lib/hexdump.rb +50 -0
- data/vendor/httpclient/lib/http-access2.rb +55 -0
- data/vendor/httpclient/lib/http-access2/cookie.rb +1 -0
- data/vendor/httpclient/lib/http-access2/http.rb +1 -0
- data/vendor/httpclient/lib/httpclient.rb +1156 -0
- data/vendor/httpclient/lib/httpclient/auth.rb +899 -0
- data/vendor/httpclient/lib/httpclient/cacert.p7s +1912 -0
- data/vendor/httpclient/lib/httpclient/connection.rb +88 -0
- data/vendor/httpclient/lib/httpclient/cookie.rb +438 -0
- data/vendor/httpclient/lib/httpclient/http.rb +1046 -0
- data/vendor/httpclient/lib/httpclient/include_client.rb +83 -0
- data/vendor/httpclient/lib/httpclient/session.rb +1025 -0
- data/vendor/httpclient/lib/httpclient/ssl_config.rb +403 -0
- data/vendor/httpclient/lib/httpclient/timeout.rb +140 -0
- data/vendor/httpclient/lib/httpclient/util.rb +178 -0
- data/vendor/httpclient/lib/httpclient/version.rb +3 -0
- data/vendor/httpclient/lib/oauthclient.rb +110 -0
- data/vendor/httpclient/sample/async.rb +8 -0
- data/vendor/httpclient/sample/auth.rb +11 -0
- data/vendor/httpclient/sample/cookie.rb +18 -0
- data/vendor/httpclient/sample/dav.rb +103 -0
- data/vendor/httpclient/sample/howto.rb +49 -0
- data/vendor/httpclient/sample/oauth_buzz.rb +57 -0
- data/vendor/httpclient/sample/oauth_friendfeed.rb +59 -0
- data/vendor/httpclient/sample/oauth_salesforce_10.rb +63 -0
- data/vendor/httpclient/sample/oauth_twitter.rb +61 -0
- data/vendor/httpclient/sample/ssl/0cert.pem +22 -0
- data/vendor/httpclient/sample/ssl/0key.pem +30 -0
- data/vendor/httpclient/sample/ssl/1000cert.pem +19 -0
- data/vendor/httpclient/sample/ssl/1000key.pem +18 -0
- data/vendor/httpclient/sample/ssl/htdocs/index.html +10 -0
- data/vendor/httpclient/sample/ssl/ssl_client.rb +22 -0
- data/vendor/httpclient/sample/ssl/webrick_httpsd.rb +29 -0
- data/vendor/httpclient/sample/stream.rb +21 -0
- data/vendor/httpclient/sample/thread.rb +27 -0
- data/vendor/httpclient/sample/wcat.rb +21 -0
- data/vendor/httpclient/test/ca-chain.cert +44 -0
- data/vendor/httpclient/test/ca.cert +23 -0
- data/vendor/httpclient/test/client.cert +19 -0
- data/vendor/httpclient/test/client.key +15 -0
- data/vendor/httpclient/test/helper.rb +129 -0
- data/vendor/httpclient/test/htdigest +1 -0
- data/vendor/httpclient/test/htpasswd +2 -0
- data/vendor/httpclient/test/runner.rb +2 -0
- data/vendor/httpclient/test/server.cert +19 -0
- data/vendor/httpclient/test/server.key +15 -0
- data/vendor/httpclient/test/sslsvr.rb +65 -0
- data/vendor/httpclient/test/subca.cert +21 -0
- data/vendor/httpclient/test/test_auth.rb +321 -0
- data/vendor/httpclient/test/test_cookie.rb +391 -0
- data/vendor/httpclient/test/test_hexdump.rb +14 -0
- data/vendor/httpclient/test/test_http-access2.rb +507 -0
- data/vendor/httpclient/test/test_httpclient.rb +1783 -0
- data/vendor/httpclient/test/test_include_client.rb +52 -0
- data/vendor/httpclient/test/test_ssl.rb +235 -0
- data/vendor/multi_json/.document +5 -0
- data/vendor/multi_json/.rspec +3 -0
- data/vendor/multi_json/.travis.yml +11 -0
- data/vendor/multi_json/.yardopts +6 -0
- data/vendor/multi_json/CHANGELOG.md +169 -0
- data/vendor/multi_json/CONTRIBUTING.md +46 -0
- data/vendor/multi_json/Gemfile +31 -0
- data/vendor/multi_json/LICENSE.md +20 -0
- data/vendor/multi_json/README.md +109 -0
- data/vendor/multi_json/Rakefile +12 -0
- data/vendor/multi_json/lib/multi_json.rb +157 -0
- data/vendor/multi_json/lib/multi_json/adapter.rb +48 -0
- data/vendor/multi_json/lib/multi_json/adapters/gson.rb +19 -0
- data/vendor/multi_json/lib/multi_json/adapters/jr_jackson.rb +19 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_common.rb +25 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_gem.rb +11 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_pure.rb +11 -0
- data/vendor/multi_json/lib/multi_json/adapters/nsjsonserialization.rb +34 -0
- data/vendor/multi_json/lib/multi_json/adapters/oj.rb +24 -0
- data/vendor/multi_json/lib/multi_json/adapters/ok_json.rb +22 -0
- data/vendor/multi_json/lib/multi_json/adapters/yajl.rb +19 -0
- data/vendor/multi_json/lib/multi_json/convertible_hash_keys.rb +43 -0
- data/vendor/multi_json/lib/multi_json/load_error.rb +11 -0
- data/vendor/multi_json/lib/multi_json/options.rb +48 -0
- data/vendor/multi_json/lib/multi_json/vendor/okjson.rb +606 -0
- data/vendor/multi_json/lib/multi_json/version.rb +20 -0
- data/vendor/multi_json/multi_json.gemspec +22 -0
- data/vendor/multi_json/spec/adapter_shared_example.rb +235 -0
- data/vendor/multi_json/spec/has_options.rb +119 -0
- data/vendor/multi_json/spec/helper.rb +35 -0
- data/vendor/multi_json/spec/json_common_shared_example.rb +30 -0
- data/vendor/multi_json/spec/multi_json_spec.rb +226 -0
- data/vendor/{signature → pusher}/.document +0 -0
- data/vendor/{json_pure/diagrams/.keep → pusher/.gemtest} +0 -0
- data/vendor/pusher/.gitignore +23 -0
- data/vendor/pusher/.travis.yml +15 -0
- data/vendor/pusher/Gemfile +2 -0
- data/vendor/{pusher-gem → pusher}/LICENSE +1 -1
- data/vendor/pusher/README.md +186 -0
- data/vendor/{pusher-gem → pusher}/Rakefile +0 -0
- data/vendor/{pusher-gem → pusher}/examples/async_message.rb +0 -0
- data/vendor/pusher/lib/pusher.rb +60 -0
- data/vendor/{pusher-gem → pusher}/lib/pusher/channel.rb +47 -54
- data/vendor/pusher/lib/pusher/client.rb +306 -0
- data/vendor/pusher/lib/pusher/request.rb +107 -0
- data/vendor/pusher/lib/pusher/resource.rb +36 -0
- data/vendor/pusher/lib/pusher/webhook.rb +110 -0
- data/vendor/{pusher-gem → pusher}/pusher.gemspec +6 -5
- data/vendor/pusher/spec/channel_spec.rb +127 -0
- data/vendor/pusher/spec/client_spec.rb +464 -0
- data/vendor/{pusher-gem → pusher}/spec/spec_helper.rb +12 -0
- data/vendor/pusher/spec/web_hook_spec.rb +117 -0
- data/vendor/signature/.travis.yml +15 -0
- data/vendor/signature/Gemfile +1 -1
- data/vendor/signature/README.md +38 -28
- data/vendor/signature/lib/signature.rb +97 -15
- data/vendor/signature/lib/signature/query_encoder.rb +47 -0
- data/vendor/signature/lib/signature/version.rb +1 -1
- data/vendor/signature/signature.gemspec +3 -2
- data/vendor/signature/spec/signature_spec.rb +164 -55
- data/vendor/signature/spec/spec_helper.rb +2 -3
- metadata +120 -145
- data/vendor/json_pure/.gitignore +0 -12
- data/vendor/json_pure/.travis.yml +0 -20
- data/vendor/json_pure/CHANGES +0 -282
- data/vendor/json_pure/COPYING +0 -58
- data/vendor/json_pure/COPYING-json-jruby +0 -57
- data/vendor/json_pure/GPL +0 -340
- data/vendor/json_pure/Gemfile +0 -11
- data/vendor/json_pure/README-json-jruby.markdown +0 -33
- data/vendor/json_pure/README.rdoc +0 -358
- data/vendor/json_pure/Rakefile +0 -412
- data/vendor/json_pure/TODO +0 -1
- data/vendor/json_pure/VERSION +0 -1
- data/vendor/json_pure/data/example.json +0 -1
- data/vendor/json_pure/data/index.html +0 -38
- data/vendor/json_pure/data/prototype.js +0 -4184
- data/vendor/json_pure/ext/json/ext/fbuffer/fbuffer.h +0 -181
- data/vendor/json_pure/ext/json/ext/generator/depend +0 -1
- data/vendor/json_pure/ext/json/ext/generator/extconf.rb +0 -14
- data/vendor/json_pure/ext/json/ext/generator/generator.c +0 -1435
- data/vendor/json_pure/ext/json/ext/generator/generator.h +0 -148
- data/vendor/json_pure/ext/json/ext/parser/depend +0 -1
- data/vendor/json_pure/ext/json/ext/parser/extconf.rb +0 -13
- data/vendor/json_pure/ext/json/ext/parser/parser.c +0 -2204
- data/vendor/json_pure/ext/json/ext/parser/parser.h +0 -77
- data/vendor/json_pure/ext/json/ext/parser/parser.rl +0 -927
- data/vendor/json_pure/install.rb +0 -23
- data/vendor/json_pure/java/src/json/ext/ByteListTranscoder.java +0 -167
- data/vendor/json_pure/java/src/json/ext/Generator.java +0 -444
- data/vendor/json_pure/java/src/json/ext/GeneratorMethods.java +0 -232
- data/vendor/json_pure/java/src/json/ext/GeneratorService.java +0 -43
- data/vendor/json_pure/java/src/json/ext/GeneratorState.java +0 -543
- data/vendor/json_pure/java/src/json/ext/OptionsReader.java +0 -114
- data/vendor/json_pure/java/src/json/ext/Parser.java +0 -2644
- data/vendor/json_pure/java/src/json/ext/Parser.rl +0 -968
- data/vendor/json_pure/java/src/json/ext/ParserService.java +0 -35
- data/vendor/json_pure/java/src/json/ext/RuntimeInfo.java +0 -121
- data/vendor/json_pure/java/src/json/ext/StringDecoder.java +0 -167
- data/vendor/json_pure/java/src/json/ext/StringEncoder.java +0 -106
- data/vendor/json_pure/java/src/json/ext/Utils.java +0 -89
- data/vendor/json_pure/json-java.gemspec +0 -23
- data/vendor/json_pure/json.gemspec +0 -37
- data/vendor/json_pure/json_pure.gemspec +0 -39
- data/vendor/json_pure/lib/json.rb +0 -62
- data/vendor/json_pure/lib/json/add/bigdecimal.rb +0 -28
- data/vendor/json_pure/lib/json/add/complex.rb +0 -22
- data/vendor/json_pure/lib/json/add/core.rb +0 -11
- data/vendor/json_pure/lib/json/add/date.rb +0 -34
- data/vendor/json_pure/lib/json/add/date_time.rb +0 -50
- data/vendor/json_pure/lib/json/add/exception.rb +0 -31
- data/vendor/json_pure/lib/json/add/ostruct.rb +0 -31
- data/vendor/json_pure/lib/json/add/range.rb +0 -29
- data/vendor/json_pure/lib/json/add/rational.rb +0 -22
- data/vendor/json_pure/lib/json/add/regexp.rb +0 -30
- data/vendor/json_pure/lib/json/add/struct.rb +0 -30
- data/vendor/json_pure/lib/json/add/symbol.rb +0 -25
- data/vendor/json_pure/lib/json/add/time.rb +0 -38
- data/vendor/json_pure/lib/json/common.rb +0 -487
- data/vendor/json_pure/lib/json/ext.rb +0 -21
- data/vendor/json_pure/lib/json/ext/.keep +0 -0
- data/vendor/json_pure/lib/json/generic_object.rb +0 -70
- data/vendor/json_pure/lib/json/pure.rb +0 -21
- data/vendor/json_pure/lib/json/pure/generator.rb +0 -522
- data/vendor/json_pure/lib/json/pure/parser.rb +0 -359
- data/vendor/json_pure/lib/json/version.rb +0 -8
- data/vendor/json_pure/tests/fixtures/fail1.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail10.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail11.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail12.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail13.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail14.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail18.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail19.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail2.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail20.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail21.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail22.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail23.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail24.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail25.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail27.json +0 -2
- data/vendor/json_pure/tests/fixtures/fail28.json +0 -2
- data/vendor/json_pure/tests/fixtures/fail3.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail4.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail5.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail6.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail7.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail8.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail9.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass1.json +0 -56
- data/vendor/json_pure/tests/fixtures/pass15.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass16.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass17.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass2.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass26.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass3.json +0 -6
- data/vendor/json_pure/tests/setup_variant.rb +0 -11
- data/vendor/json_pure/tests/test_json.rb +0 -545
- data/vendor/json_pure/tests/test_json_addition.rb +0 -196
- data/vendor/json_pure/tests/test_json_encoding.rb +0 -65
- data/vendor/json_pure/tests/test_json_fixtures.rb +0 -35
- data/vendor/json_pure/tests/test_json_generate.rb +0 -322
- data/vendor/json_pure/tests/test_json_generic_object.rb +0 -75
- data/vendor/json_pure/tests/test_json_string_matching.rb +0 -39
- data/vendor/json_pure/tests/test_json_unicode.rb +0 -72
- data/vendor/json_pure/tools/fuzz.rb +0 -139
- data/vendor/json_pure/tools/server.rb +0 -62
- data/vendor/pusher-gem/Gemfile +0 -2
- data/vendor/pusher-gem/README.md +0 -80
- data/vendor/pusher-gem/lib/pusher.rb +0 -107
- data/vendor/pusher-gem/lib/pusher/request.rb +0 -107
- data/vendor/pusher-gem/spec/channel_spec.rb +0 -274
- data/vendor/pusher-gem/spec/pusher_spec.rb +0 -87
- data/vendor/ruby-hmac/History.txt +0 -15
- data/vendor/ruby-hmac/Manifest.txt +0 -11
- data/vendor/ruby-hmac/README.md +0 -41
- data/vendor/ruby-hmac/Rakefile +0 -23
- data/vendor/ruby-hmac/lib/hmac-md5.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-rmd160.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-sha1.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-sha2.rb +0 -25
- data/vendor/ruby-hmac/lib/hmac.rb +0 -118
- data/vendor/ruby-hmac/lib/ruby_hmac.rb +0 -2
- data/vendor/ruby-hmac/ruby-hmac.gemspec +0 -33
- data/vendor/ruby-hmac/test/test_hmac.rb +0 -89
- data/vendor/signature/VERSION +0 -1
|
@@ -11,3 +11,15 @@ require 'webmock/rspec'
|
|
|
11
11
|
|
|
12
12
|
require 'pusher'
|
|
13
13
|
require 'eventmachine'
|
|
14
|
+
|
|
15
|
+
RSpec.configure do |config|
|
|
16
|
+
config.before(:each) do
|
|
17
|
+
WebMock.reset!
|
|
18
|
+
WebMock.disable_net_connect!
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def hmac(key, data)
|
|
23
|
+
digest = OpenSSL::Digest::SHA256.new
|
|
24
|
+
OpenSSL::HMAC.hexdigest(digest, key, data)
|
|
25
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
wh.key.should == '1234'
|
|
26
|
+
wh.signature.should == 'asdf'
|
|
27
|
+
wh.data.should == @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
|
+
wh.key.should == '1234'
|
|
39
|
+
wh.signature.should == 'asdf'
|
|
40
|
+
wh.data.should == @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
|
+
@wh.should be_valid
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should not validate if key is wrong" do
|
|
65
|
+
@client.key = '12345'
|
|
66
|
+
@client.secret = 'asdf'
|
|
67
|
+
Pusher.logger.should_receive(:warn).with("Received webhook with unknown key: 1234")
|
|
68
|
+
@wh.should_not 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
|
+
Pusher.logger.should_receive(:warn).with("Received WebHook with invalid signature: got #{@wh.signature}, expected #{expected}")
|
|
77
|
+
@wh.should_not be_valid
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should validate with an extra token" do
|
|
81
|
+
@client.key = '12345'
|
|
82
|
+
@client.secret = 'xxx'
|
|
83
|
+
@wh.valid?({:key => '1234', :secret => 'asdf'}).should be_true
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "should validate with an array of extra tokens" do
|
|
87
|
+
@client.key = '123456'
|
|
88
|
+
@client.secret = 'xxx'
|
|
89
|
+
@wh.valid?([
|
|
90
|
+
{:key => '12345', :secret => 'wtf'},
|
|
91
|
+
{:key => '1234', :secret => 'asdf'}
|
|
92
|
+
]).should be_true
|
|
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
|
+
Pusher.logger.should_receive(:warn).with("Received webhook with unknown key: 1234")
|
|
99
|
+
@wh.valid?({:key => '12345', :secret => 'asdf'}).should be_false
|
|
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
|
+
Pusher.logger.should_receive(:warn).with(/Received WebHook with invalid signature/)
|
|
106
|
+
@wh.valid?({:key => '1234', :secret => 'wtf'}).should be_false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should expose events" do
|
|
110
|
+
@wh.events.should == @hook_data["events"]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should expose time" do
|
|
114
|
+
@wh.time.should == Time.at(123.456)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
rvm:
|
|
3
|
+
- 1.8.7
|
|
4
|
+
- 1.9.2
|
|
5
|
+
- 1.9.3
|
|
6
|
+
- jruby-18mode # JRuby in 1.8 mode
|
|
7
|
+
- jruby-19mode # JRuby in 1.9 mode
|
|
8
|
+
- rbx-18mode
|
|
9
|
+
- rbx-19mode
|
|
10
|
+
matrix:
|
|
11
|
+
allow_failures:
|
|
12
|
+
- rvm: rbx-18mode
|
|
13
|
+
- rvm: rbx-19mode
|
|
14
|
+
|
|
15
|
+
script: bundle exec rspec spec
|
data/vendor/signature/Gemfile
CHANGED
data/vendor/signature/README.md
CHANGED
|
@@ -1,47 +1,55 @@
|
|
|
1
1
|
signature
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
[](http://travis-ci.org/mloughran/signature)
|
|
5
|
+
|
|
4
6
|
Examples
|
|
5
7
|
--------
|
|
6
8
|
|
|
7
9
|
Client example
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
```ruby
|
|
12
|
+
params = {:some => 'parameters'}
|
|
13
|
+
token = Signature::Token.new('my_key', 'my_secret')
|
|
14
|
+
request = Signature::Request.new('POST', '/api/thing', params)
|
|
15
|
+
auth_hash = request.sign(token)
|
|
16
|
+
query_params = params.merge(auth_hash)
|
|
17
|
+
|
|
18
|
+
HTTParty.post('http://myservice/api/thing', {
|
|
19
|
+
:query => query_params
|
|
20
|
+
})
|
|
21
|
+
```
|
|
18
22
|
|
|
19
23
|
`query_params` looks like:
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
```ruby
|
|
26
|
+
{
|
|
27
|
+
:some => "parameters",
|
|
28
|
+
:auth_timestamp => 1273231888,
|
|
29
|
+
:auth_signature => "28b6bb0f242f71064916fad6ae463fe91f5adc302222dfc02c348ae1941eaf80",
|
|
30
|
+
:auth_version => "1.0",
|
|
31
|
+
:auth_key => "my_key"
|
|
32
|
+
}
|
|
28
33
|
|
|
34
|
+
```
|
|
29
35
|
Server example (sinatra)
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
```ruby
|
|
38
|
+
error Signature::AuthenticationError do |controller|
|
|
39
|
+
error = controller.env["sinatra.error"]
|
|
40
|
+
halt 401, "401 UNAUTHORIZED: #{error.message}\n"
|
|
41
|
+
end
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
post '/api/thing' do
|
|
44
|
+
request = Signature::Request.new('POST', env["REQUEST_PATH"], params)
|
|
45
|
+
# This will raise a Signature::AuthenticationError if request does not authenticate
|
|
46
|
+
token = request.authenticate do |key|
|
|
47
|
+
Signature::Token.new(key, lookup_secret(key))
|
|
48
|
+
end
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
# Do whatever you need to do
|
|
51
|
+
end
|
|
52
|
+
```
|
|
45
53
|
|
|
46
54
|
Developing
|
|
47
55
|
----------
|
|
@@ -49,6 +57,8 @@ Developing
|
|
|
49
57
|
bundle
|
|
50
58
|
bundle exec rspec spec/*_spec.rb
|
|
51
59
|
|
|
60
|
+
Please see the travis status for a list of rubies tested against
|
|
61
|
+
|
|
52
62
|
Copyright
|
|
53
63
|
---------
|
|
54
64
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'openssl'
|
|
2
|
+
|
|
3
|
+
require 'signature/query_encoder'
|
|
2
4
|
|
|
3
5
|
module Signature
|
|
4
6
|
class AuthenticationError < RuntimeError; end
|
|
@@ -18,6 +20,8 @@ module Signature
|
|
|
18
20
|
class Request
|
|
19
21
|
attr_accessor :path, :query_hash
|
|
20
22
|
|
|
23
|
+
include QueryEncoder
|
|
24
|
+
|
|
21
25
|
# http://www.w3.org/TR/NOTE-datetime
|
|
22
26
|
ISO8601 = "%Y-%m-%dT%H:%M:%SZ"
|
|
23
27
|
|
|
@@ -34,63 +38,139 @@ module Signature
|
|
|
34
38
|
|
|
35
39
|
@method = method.upcase
|
|
36
40
|
@path, @query_hash, @auth_hash = path, query_hash, auth_hash
|
|
41
|
+
@signed = false
|
|
37
42
|
end
|
|
38
43
|
|
|
44
|
+
# Sign the request with the given token, and return the computed
|
|
45
|
+
# authentication parameters
|
|
46
|
+
#
|
|
39
47
|
def sign(token)
|
|
40
48
|
@auth_hash = {
|
|
41
49
|
:auth_version => "1.0",
|
|
42
50
|
:auth_key => token.key,
|
|
43
51
|
:auth_timestamp => Time.now.to_i.to_s
|
|
44
52
|
}
|
|
45
|
-
|
|
46
53
|
@auth_hash[:auth_signature] = signature(token)
|
|
47
54
|
|
|
55
|
+
@signed = true
|
|
56
|
+
|
|
48
57
|
return @auth_hash
|
|
49
58
|
end
|
|
50
59
|
|
|
51
60
|
# Authenticates the request with a token
|
|
52
61
|
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
62
|
+
# Raises an AuthenticationError if the request is invalid.
|
|
63
|
+
# AuthenticationError exception messages are designed to be exposed to API
|
|
64
|
+
# consumers, and should help them correct errors generating signatures
|
|
65
|
+
#
|
|
66
|
+
# Timestamp: Unless timestamp_grace is set to nil (which allows this check
|
|
67
|
+
# to be skipped), AuthenticationError will be raised if the timestamp is
|
|
68
|
+
# missing or further than timestamp_grace period away from the real time
|
|
69
|
+
# (defaults to 10 minutes)
|
|
57
70
|
#
|
|
58
|
-
# Signature
|
|
59
|
-
# computed
|
|
71
|
+
# Signature: Raises AuthenticationError if the signature does not match
|
|
72
|
+
# the computed HMAC. The error contains a hint for how to sign.
|
|
60
73
|
#
|
|
61
74
|
def authenticate_by_token!(token, timestamp_grace = 600)
|
|
75
|
+
# Validate that your code has provided a valid token. This does not
|
|
76
|
+
# raise an AuthenticationError since passing tokens with empty secret is
|
|
77
|
+
# a code error which should be fixed, not reported to the API's consumer
|
|
78
|
+
if token.secret.nil? || token.secret.empty?
|
|
79
|
+
raise "Provided token is missing secret"
|
|
80
|
+
end
|
|
81
|
+
|
|
62
82
|
validate_version!
|
|
63
83
|
validate_timestamp!(timestamp_grace)
|
|
64
84
|
validate_signature!(token)
|
|
65
85
|
true
|
|
66
86
|
end
|
|
67
87
|
|
|
88
|
+
# Authenticate the request with a token, but rather than raising an
|
|
89
|
+
# exception if the request is invalid, simply returns false
|
|
90
|
+
#
|
|
68
91
|
def authenticate_by_token(token, timestamp_grace = 600)
|
|
69
92
|
authenticate_by_token!(token, timestamp_grace)
|
|
70
93
|
rescue AuthenticationError
|
|
71
94
|
false
|
|
72
95
|
end
|
|
73
96
|
|
|
74
|
-
|
|
97
|
+
# Authenticate a request
|
|
98
|
+
#
|
|
99
|
+
# Takes a block which will be called with the auth_key from the request,
|
|
100
|
+
# and which should return a Signature::Token (or nil if no token can be
|
|
101
|
+
# found for the key)
|
|
102
|
+
#
|
|
103
|
+
# Raises errors in the same way as authenticate_by_token!
|
|
104
|
+
#
|
|
105
|
+
def authenticate(timestamp_grace = 600)
|
|
106
|
+
raise ArgumentError, "Block required" unless block_given?
|
|
75
107
|
key = @auth_hash['auth_key']
|
|
76
|
-
raise AuthenticationError, "
|
|
108
|
+
raise AuthenticationError, "Missing parameter: auth_key" unless key
|
|
77
109
|
token = yield key
|
|
78
|
-
unless token
|
|
79
|
-
raise AuthenticationError, "
|
|
110
|
+
unless token
|
|
111
|
+
raise AuthenticationError, "Unknown auth_key"
|
|
80
112
|
end
|
|
81
113
|
authenticate_by_token!(token, timestamp_grace)
|
|
82
114
|
return token
|
|
83
115
|
end
|
|
84
116
|
|
|
117
|
+
# Authenticate a request asynchronously
|
|
118
|
+
#
|
|
119
|
+
# This method is useful it you're running a server inside eventmachine and
|
|
120
|
+
# need to lookup the token asynchronously.
|
|
121
|
+
#
|
|
122
|
+
# The block is passed an auth key and a deferrable which should succeed
|
|
123
|
+
# with the token, or fail if the token cannot be found
|
|
124
|
+
#
|
|
125
|
+
# This method returns a deferrable which succeeds with the valid token, or
|
|
126
|
+
# fails with an AuthenticationError which can be used to pass the error
|
|
127
|
+
# back to the user
|
|
128
|
+
#
|
|
129
|
+
def authenticate_async(timestamp_grace = 600)
|
|
130
|
+
raise ArgumentError, "Block required" unless block_given?
|
|
131
|
+
df = EM::DefaultDeferrable.new
|
|
132
|
+
|
|
133
|
+
key = @auth_hash['auth_key']
|
|
134
|
+
|
|
135
|
+
unless key
|
|
136
|
+
df.fail(AuthenticationError.new("Missing parameter: auth_key"))
|
|
137
|
+
return
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
token_df = yield key
|
|
141
|
+
token_df.callback { |token|
|
|
142
|
+
begin
|
|
143
|
+
authenticate_by_token!(token, timestamp_grace)
|
|
144
|
+
df.succeed(token)
|
|
145
|
+
rescue AuthenticationError => e
|
|
146
|
+
df.fail(e)
|
|
147
|
+
end
|
|
148
|
+
}
|
|
149
|
+
token_df.errback {
|
|
150
|
+
df.fail(AuthenticationError.new("Unknown auth_key"))
|
|
151
|
+
}
|
|
152
|
+
ensure
|
|
153
|
+
return df
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Expose the authentication parameters for a signed request
|
|
157
|
+
#
|
|
85
158
|
def auth_hash
|
|
86
|
-
raise "Request not signed" unless @
|
|
159
|
+
raise "Request not signed" unless @signed
|
|
87
160
|
@auth_hash
|
|
88
161
|
end
|
|
89
162
|
|
|
163
|
+
# Query parameters merged with the computed authentication parameters
|
|
164
|
+
#
|
|
165
|
+
def signed_params
|
|
166
|
+
@query_hash.merge(auth_hash)
|
|
167
|
+
end
|
|
168
|
+
|
|
90
169
|
private
|
|
91
170
|
|
|
92
171
|
def signature(token)
|
|
93
|
-
|
|
172
|
+
digest = OpenSSL::Digest::SHA256.new
|
|
173
|
+
OpenSSL::HMAC.hexdigest(digest, token.secret, string_to_sign)
|
|
94
174
|
end
|
|
95
175
|
|
|
96
176
|
def string_to_sign
|
|
@@ -106,7 +186,9 @@ module Signature
|
|
|
106
186
|
# Exclude signature from signature generation!
|
|
107
187
|
hash.delete("auth_signature")
|
|
108
188
|
|
|
109
|
-
hash.
|
|
189
|
+
hash.sort.map do |k, v|
|
|
190
|
+
QueryEncoder.encode_param_without_escaping(k, v)
|
|
191
|
+
end.join('&')
|
|
110
192
|
end
|
|
111
193
|
|
|
112
194
|
def validate_version!
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Signature
|
|
2
|
+
# Query string encoding extracted with thanks from em-http-request
|
|
3
|
+
module QueryEncoder
|
|
4
|
+
class << self
|
|
5
|
+
# URL encodes query parameters:
|
|
6
|
+
# single k=v, or a URL encoded array, if v is an array of values
|
|
7
|
+
def encode_param(k, v)
|
|
8
|
+
if v.is_a?(Array)
|
|
9
|
+
v.map { |e| escape(k) + "[]=" + escape(e) }.join("&")
|
|
10
|
+
else
|
|
11
|
+
escape(k) + "=" + escape(v)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Like encode_param, but doesn't url escape keys or values
|
|
16
|
+
def encode_param_without_escaping(k, v)
|
|
17
|
+
if v.is_a?(Array)
|
|
18
|
+
v.map { |e| k + "[]=" + e }.join("&")
|
|
19
|
+
else
|
|
20
|
+
"#{k}=#{v}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def escape(s)
|
|
27
|
+
if defined?(EscapeUtils)
|
|
28
|
+
EscapeUtils.escape_url(s.to_s)
|
|
29
|
+
else
|
|
30
|
+
s.to_s.gsub(/([^a-zA-Z0-9_.-]+)/n) {
|
|
31
|
+
'%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if ''.respond_to?(:bytesize)
|
|
37
|
+
def bytesize(string)
|
|
38
|
+
string.bytesize
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
def bytesize(string)
|
|
42
|
+
string.size
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|